diff --git a/backend/package-lock.json b/backend/package-lock.json index 58dd2da2..df75af75 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -53,14 +53,14 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/@electric-sql/pglite/-/pglite-0.4.1.tgz", "integrity": "sha512-mZ9NzzUSYPOCnxHH1oAHPRzoMFJHY472raDKwXl/+6oPbpdJ7g8LsCN4FSaIIfkiCKHhb3iF/Zqo3NYxaIhU7Q==", - "dev": true, + "devOptional": true, "license": "Apache-2.0" }, "node_modules/@electric-sql/pglite-socket": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/@electric-sql/pglite-socket/-/pglite-socket-0.1.1.tgz", "integrity": "sha512-p2hoXw3Z3LQHwTeikdZNsFBOvXGqKY2hk51BBw+8NKND8eoH+8LFOtW9Z8CQKmTJ2qqGYu82ipqiyFZOTTXNfw==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "bin": { "pglite-server": "dist/scripts/server.js" @@ -73,7 +73,7 @@ "version": "0.3.1", "resolved": "https://registry.npmjs.org/@electric-sql/pglite-tools/-/pglite-tools-0.3.1.tgz", "integrity": "sha512-C+T3oivmy9bpQvSxVqXA1UDY8cB9Eb9vZHL9zxWwEUfDixbXv4G3r2LjoTdR33LD8aomR3O9ZXEO3XEwr/cUCA==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "peerDependencies": { "@electric-sql/pglite": "0.4.1" @@ -83,7 +83,7 @@ "version": "1.19.11", "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.11.tgz", "integrity": "sha512-dr8/3zEaB+p0D2n/IUrlPF1HZm586qgJNXK1a9fhg/PzdtkK7Ksd5l312tJX2yBuALqDYBlG20QEbayqPyxn+g==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=18.14.1" @@ -130,7 +130,7 @@ "version": "0.3.4", "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.4.tgz", "integrity": "sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@msgpackr-extract/msgpackr-extract-darwin-arm64": { @@ -284,7 +284,7 @@ "version": "7.8.0", "resolved": "https://registry.npmjs.org/@prisma/config/-/config-7.8.0.tgz", "integrity": "sha512-HFESzd9rx2ZQxlK+TL7tu1HPvCqrHiL6LCxYykI2c34mvaUuIVVl3lYuicJD/MNnzgPnyeBEMlK4WTomJCV5jw==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "dependencies": { "c12": "3.3.4", @@ -303,7 +303,7 @@ "version": "0.24.3", "resolved": "https://registry.npmjs.org/@prisma/dev/-/dev-0.24.3.tgz", "integrity": "sha512-ffHlQuKXZiaDt9Go0OnCTdJZrHxK0k7omJKNV86/VjpsXu5EIHZLK0T7JSWgvNlJwh56kW9JFu9v0qJciFzepg==", - "dev": true, + "devOptional": true, "license": "ISC", "dependencies": { "@electric-sql/pglite": "0.4.1", @@ -338,7 +338,7 @@ "version": "7.8.0", "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-7.8.0.tgz", "integrity": "sha512-jx3rCnNNrt5uzbkKlegtQ2GZHxSlihMCzutgT/BP6UIDF1r9tDI39hV/0T/cHZgzJ3ELbuQPXlVZy+Y1n0pcgw==", - "dev": true, + "devOptional": true, "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { @@ -352,14 +352,14 @@ "version": "7.8.0-6.3c6e192761c0362d496ed980de936e2f3cebcd3a", "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-7.8.0-6.3c6e192761c0362d496ed980de936e2f3cebcd3a.tgz", "integrity": "sha512-fJPQxCkLgA5EayWaW8eArgCvjJ+N+Kz3VyeNKMEeYiQC4alNkxRKFVAGxv/ZUzuJISKqdw+zGeDbS6mn6RCPOA==", - "dev": true, + "devOptional": true, "license": "Apache-2.0" }, "node_modules/@prisma/engines/node_modules/@prisma/get-platform": { "version": "7.8.0", "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-7.8.0.tgz", "integrity": "sha512-WlxgRGnolL8VH2EmkH1R/DkKNr/mVdS3G2h42IZFFZ3eUrH9OT6t73kIOSlkkrv50wG123Iq8d96ufv5LlZktw==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "dependencies": { "@prisma/debug": "7.8.0" @@ -369,7 +369,7 @@ "version": "7.8.0", "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-7.8.0.tgz", "integrity": "sha512-gwB0Euiz/DDRyxFRpLXYlK3RfaZUj1c5dAYMuhZYfApg7arknJlcb9bIsOHDppJmbqYaVA+yBIiFMDBfprsNPQ==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "dependencies": { "@prisma/debug": "7.8.0", @@ -381,7 +381,7 @@ "version": "7.8.0", "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-7.8.0.tgz", "integrity": "sha512-WlxgRGnolL8VH2EmkH1R/DkKNr/mVdS3G2h42IZFFZ3eUrH9OT6t73kIOSlkkrv50wG123Iq8d96ufv5LlZktw==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "dependencies": { "@prisma/debug": "7.8.0" @@ -391,7 +391,7 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-7.2.0.tgz", "integrity": "sha512-k1V0l0Td1732EHpAfi2eySTezyllok9dXb6UQanajkJQzPUGi3vO2z7jdkz67SypFTdmbnyGYxvEvYZdZsMAVA==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "dependencies": { "@prisma/debug": "7.2.0" @@ -401,21 +401,21 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-7.2.0.tgz", "integrity": "sha512-YSGTiSlBAVJPzX4ONZmMotL+ozJwQjRmZweQNIq/ER0tQJKJynNkRB3kyvt37eOfsbMCXk3gnLF6J9OJ4QWftw==", - "dev": true, + "devOptional": true, "license": "Apache-2.0" }, "node_modules/@prisma/query-plan-executor": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@prisma/query-plan-executor/-/query-plan-executor-7.2.0.tgz", "integrity": "sha512-EOZmNzcV8uJ0mae3DhTsiHgoNCuu1J9mULQpGCh62zN3PxPTd+qI9tJvk5jOst8WHKQNwJWR3b39t0XvfBB0WQ==", - "dev": true, + "devOptional": true, "license": "Apache-2.0" }, "node_modules/@prisma/streams-local": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/@prisma/streams-local/-/streams-local-0.1.2.tgz", "integrity": "sha512-l49yTxKKF2odFxaAXTmwmkBKL3+bVQ1tFOooGifu4xkdb9NMNLxHj27XAhTylWZod8I+ISGM5erU1xcl/oBCtg==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "dependencies": { "ajv": "^8.12.0", @@ -432,7 +432,7 @@ "version": "0.27.3", "resolved": "https://registry.npmjs.org/@prisma/studio-core/-/studio-core-0.27.3.tgz", "integrity": "sha512-AADjNFPdsrglxHQVTmHFqv6DuKQZ5WY4p5/gVFY017twvNrSwpLJ9lqUbYYxEu2W7nbvVxTZA8deJ8LseNALsw==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "dependencies": { "@radix-ui/react-toggle": "1.1.10", @@ -452,14 +452,14 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz", "integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@radix-ui/react-compose-refs": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==", - "dev": true, + "devOptional": true, "license": "MIT", "peerDependencies": { "@types/react": "*", @@ -475,7 +475,7 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@radix-ui/react-slot": "1.2.3" @@ -499,7 +499,7 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" @@ -518,7 +518,7 @@ "version": "1.1.10", "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle/-/react-toggle-1.1.10.tgz", "integrity": "sha512-lS1odchhFTeZv3xwHH31YPObmJn8gOg7Lq12inrr0+BH/l3Tsq32VfjqH1oh80ARM3mlkfMic15n0kg4sD1poQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.3", @@ -544,7 +544,7 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz", "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@radix-ui/react-use-effect-event": "0.0.2", @@ -564,7 +564,7 @@ "version": "0.0.2", "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz", "integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" @@ -583,7 +583,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz", "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==", - "dev": true, + "devOptional": true, "license": "MIT", "peerDependencies": { "@types/react": "*", @@ -599,7 +599,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@stellar/freighter-api": { @@ -827,6 +827,17 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/react": { + "version": "19.2.15", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.15.tgz", + "integrity": "sha512-eRwcGNHve+E8qtEQSSRl6urh+rFop4v8gm6O8rGv25CodbvFdLjA1vVQ1KkiFE0w0UPOnb8tDiFKL5lp0rtY5Q==", + "devOptional": true, + "license": "MIT", + "peer": true, + "dependencies": { + "csstype": "^3.2.2" + } + }, "node_modules/@types/send": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.1.tgz", @@ -891,7 +902,7 @@ "version": "8.20.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", @@ -956,7 +967,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/aws-ssl-profiles/-/aws-ssl-profiles-1.1.2.tgz", "integrity": "sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">= 6.0.0" @@ -1016,7 +1027,7 @@ "version": "2.9.2", "resolved": "https://registry.npmjs.org/better-result/-/better-result-2.9.2.tgz", "integrity": "sha512-WIFoBPCdnTOdk9inkE1ZRvCZ4P0CpSkAiLlchC65N7n9DcjZ3NhqkBOlafzpOVnO8ixyi37kicmSJ3ENhPZl7Q==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/bignumber.js": { @@ -1176,7 +1187,7 @@ "version": "3.3.4", "resolved": "https://registry.npmjs.org/c12/-/c12-3.3.4.tgz", "integrity": "sha512-cM0ApFQSBXuourJejzwv/AuPRvAxordTyParRVcHjjtXirtkzM0uK2L9TTn9s0cXZbG7E55jCivRQzoxYmRAlA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "chokidar": "^5.0.0", @@ -1205,7 +1216,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "readdirp": "^5.0.0" @@ -1221,7 +1232,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">= 20.19.0" @@ -1282,7 +1293,7 @@ "version": "4.5.1", "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.5.1.tgz", "integrity": "sha512-GIjfiT9dbmHRiYi6Nl2yFCq7kkwdkp1W/lp2J99rX0yo9tgJGn3lKQATztIjb5tVtevcBtIdICNWqlq5+E8/Pw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@kurkle/color": "^0.3.0" @@ -1365,7 +1376,7 @@ "version": "0.2.4", "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.4.tgz", "integrity": "sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/content-disposition": { @@ -1448,7 +1459,7 @@ "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "path-key": "^3.1.0", @@ -1459,6 +1470,14 @@ "node": ">= 8" } }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "devOptional": true, + "license": "MIT", + "peer": true + }, "node_modules/debug": { "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", @@ -1480,7 +1499,7 @@ "version": "7.1.5", "resolved": "https://registry.npmjs.org/deepmerge-ts/-/deepmerge-ts-7.1.5.tgz", "integrity": "sha512-HOJkrhaYsweh+W+e74Yn7YStZOilkoPb6fycpwNLKzSPtruFs48nYis0zy5yJz1+ktUhHxoRDJ27RQAWLIJVJw==", - "dev": true, + "devOptional": true, "license": "BSD-3-Clause", "engines": { "node": ">=16.0.0" @@ -1507,7 +1526,7 @@ "version": "6.1.7", "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.7.tgz", "integrity": "sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/delayed-stream": { @@ -1541,7 +1560,7 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/destr/-/destr-2.0.5.tgz", "integrity": "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/detect-libc": { @@ -1609,7 +1628,7 @@ "version": "3.20.0", "resolved": "https://registry.npmjs.org/effect/-/effect-3.20.0.tgz", "integrity": "sha512-qMLfDJscrNG8p/aw+IkT9W7fgj50Z4wG5bLBy0Txsxz8iUHjDIkOgO3SV0WZfnQbNG2VJYb0b+rDLMrhM4+Krw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@standard-schema/spec": "^1.0.0", @@ -1620,7 +1639,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/empathic/-/empathic-2.0.0.tgz", "integrity": "sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=14" @@ -1639,7 +1658,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-3.0.0.tgz", "integrity": "sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": "^12.20.0 || ^14.13.1 || >=16.0.0" @@ -1764,14 +1783,14 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.8.tgz", "integrity": "sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/fast-check": { "version": "3.23.2", "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-3.23.2.tgz", "integrity": "sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A==", - "dev": true, + "devOptional": true, "funding": [ { "type": "individual", @@ -1794,14 +1813,14 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/fast-uri": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.2.tgz", "integrity": "sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==", - "dev": true, + "devOptional": true, "funding": [ { "type": "github", @@ -1896,7 +1915,7 @@ "version": "3.3.1", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", - "dev": true, + "devOptional": true, "license": "ISC", "dependencies": { "cross-spawn": "^7.0.6", @@ -1992,7 +2011,7 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "is-property": "^1.0.2" @@ -2026,7 +2045,7 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/get-port-please/-/get-port-please-3.2.0.tgz", "integrity": "sha512-I9QVvBw5U/hw3RmWpYKRumUeaDgxTPd401x364rLmWBJcOQ753eov1eTgzDqRG9bqFIfDc7gfzcQEWrUri3o1A==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/get-proto": { @@ -2046,7 +2065,7 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/giget/-/giget-3.2.0.tgz", "integrity": "sha512-GvHTWcykIR/fP8cj8dMpuMMkvaeJfPvYnhq0oW+chSeIr+ldX21ifU2Ms6KBoyKZQZmVaUAAhQ2EZ68KJF8a7A==", - "dev": true, + "devOptional": true, "license": "MIT", "bin": { "giget": "dist/cli.mjs" @@ -2081,21 +2100,21 @@ "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true, + "devOptional": true, "license": "ISC" }, "node_modules/grammex": { "version": "3.1.12", "resolved": "https://registry.npmjs.org/grammex/-/grammex-3.1.12.tgz", "integrity": "sha512-6ufJOsSA7LcQehIJNCO7HIBykfM7DXQual0Ny780/DEcJIpBlHRvcqEBWGPYd7hrXL2GJ3oJI1MIhaXjWmLQOQ==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/graphmatch": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/graphmatch/-/graphmatch-1.1.1.tgz", "integrity": "sha512-5ykVn/EXM1hF0XCaWh05VbYvEiOL2lY1kBxZtaYsyvjp7cmWOU1XsAdfQBwClraEofXDT197lFbXOEVMHpvQOg==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/has-flag": { @@ -2163,7 +2182,7 @@ "version": "4.12.23", "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.23.tgz", "integrity": "sha512-eIaZ9qDgu7XV0pxOCrg7/WhnQ6Ivm22UcxhXx/A3dcbqbbYgBEkc6e/J/s7j2tS96zoB0S9VBdLwQNCWwUo4LA==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=16.9.0" @@ -2193,7 +2212,7 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/http-status-codes/-/http-status-codes-2.3.0.tgz", "integrity": "sha512-RJ8XvFvpPM/Dmc5SV+dC4y5PCeOhT3x1Hq0NU3rjGeg5a/CqlhZ7uudknPwZFz4aeAXDcbAyaeP7GAo9lvngtA==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/iconv-lite": { @@ -2346,7 +2365,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", "integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/is-retry-allowed": { @@ -2386,14 +2405,14 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, + "devOptional": true, "license": "ISC" }, "node_modules/jiti": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz", "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==", - "dev": true, + "devOptional": true, "license": "MIT", "bin": { "jiti": "lib/jiti-cli.mjs" @@ -2403,7 +2422,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/jsonwebtoken": { @@ -2507,14 +2526,14 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", - "dev": true, + "devOptional": true, "license": "Apache-2.0" }, "node_modules/lru.min": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/lru.min/-/lru.min-1.1.4.tgz", "integrity": "sha512-DqC6n3QQ77zdFpCMASA1a3Jlb64Hv2N2DciFGkO/4L9+q/IpIAuRlKOvCXabtRW6cQf8usbmM6BE/TOPysCdIA==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "bun": ">=1.0.0", @@ -2716,7 +2735,7 @@ "version": "3.15.3", "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.15.3.tgz", "integrity": "sha512-FBrGau0IXmuqg4haEZRBfHNWB5mUARw6hNwPDXXGg0XzVJ50mr/9hb267lvpVMnhZ1FON3qNd4Xfcez1rbFwSg==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "aws-ssl-profiles": "^1.1.1", @@ -2737,7 +2756,7 @@ "version": "1.1.6", "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.6.tgz", "integrity": "sha512-Tz09sEL2EEuv5fFowm419c1+a/jSMiBjI9gHxVLrVdbUkkNUUfjsVYs9pVZu5oCon/kmRh9TfLEObFtkVxmY0w==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "lru.min": "^1.1.0" @@ -2840,7 +2859,7 @@ "version": "2.0.11", "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.11.tgz", "integrity": "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/on-finished": { @@ -2877,7 +2896,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=8" @@ -2897,14 +2916,14 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/perfect-debounce": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-2.1.0.tgz", "integrity": "sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/pg": { @@ -3022,7 +3041,7 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.1.tgz", "integrity": "sha512-y+ichcgc2LrADuhLNAx8DFjVfgz91pRxfZdI3UDhxHvcVEZsenLO+7XaU5vOp0u/7V/wZ+plyuQxtrDlZJ+yeg==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "confbox": "^0.2.4", @@ -3043,7 +3062,7 @@ "version": "3.4.7", "resolved": "https://registry.npmjs.org/postgres/-/postgres-3.4.7.tgz", "integrity": "sha512-Jtc2612XINuBjIl/QTWsV5UvE8UHuNblcO3vVADSrKsrc6RqGX6lOW1cEo3CM2v0XG4Nat8nI+YM7/f26VxXLw==", - "dev": true, + "devOptional": true, "license": "Unlicense", "engines": { "node": ">=12" @@ -3096,7 +3115,7 @@ "version": "7.8.0", "resolved": "https://registry.npmjs.org/prisma/-/prisma-7.8.0.tgz", "integrity": "sha512-yfN4yrw7HV9kEJhoy1+jgah0jafEIQsf7uWouSsM8MvJtlubsk+kM7AIBWZ8+GJl74Yj3c+nbYqBkMOxtsZ3Lw==", - "dev": true, + "devOptional": true, "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { @@ -3130,7 +3149,7 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-4.1.2.tgz", "integrity": "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "graceful-fs": "^4.2.4", @@ -3142,7 +3161,7 @@ "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true, + "devOptional": true, "license": "ISC" }, "node_modules/proxy-addr": { @@ -3178,7 +3197,7 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", - "dev": true, + "devOptional": true, "funding": [ { "type": "individual", @@ -3243,13 +3262,38 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/rc9/-/rc9-3.0.1.tgz", "integrity": "sha512-gMDyleLWVE+i6Sgtc0QbbY6pEKqYs97NGi6isHQPqYlLemPoO8dxQ3uGi0f4NiP98c+jMW6cG1Kx9dDwfvqARQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "defu": "^6.1.6", "destr": "^2.0.5" } }, + "node_modules/react": { + "version": "19.2.6", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.6.tgz", + "integrity": "sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q==", + "devOptional": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.2.6", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.6.tgz", + "integrity": "sha512-0prMI+hvBbPjsWnxDLxlCGyM8PN6UuWjEUCYmZhO67xIV9Xasa/r/vDnq+Xyq4Lo27g8QSbO5YzARu0D1Sps3g==", + "devOptional": true, + "license": "MIT", + "peer": true, + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.6" + } + }, "node_modules/readable-stream": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", @@ -3302,7 +3346,7 @@ "version": "2.33.4", "resolved": "https://registry.npmjs.org/remeda/-/remeda-2.33.4.tgz", "integrity": "sha512-ygHswjlc/opg2VrtiYvUOPLjxjtdKvjGz1/plDhkG66hjNjFr1xmfrs2ClNFo/E6TyUFiwYNh53bKV26oBoMGQ==", - "dev": true, + "devOptional": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/remeda" @@ -3312,7 +3356,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -3322,7 +3366,7 @@ "version": "0.12.0", "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">= 4" @@ -3370,6 +3414,14 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "license": "MIT" }, + "node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "devOptional": true, + "license": "MIT", + "peer": true + }, "node_modules/semver": { "version": "7.8.0", "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.0.tgz", @@ -3412,7 +3464,7 @@ "version": "0.0.5", "resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz", "integrity": "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==", - "dev": true + "devOptional": true }, "node_modules/serve-static": { "version": "2.2.1", @@ -3480,7 +3532,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" @@ -3493,7 +3545,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=8" @@ -3575,7 +3627,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, + "devOptional": true, "license": "ISC", "engines": { "node": ">=14" @@ -3610,7 +3662,7 @@ "version": "2.3.3", "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.3.tgz", "integrity": "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -3635,7 +3687,7 @@ "version": "3.10.0", "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/streamsearch": { @@ -3825,7 +3877,7 @@ "version": "6.0.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -3880,7 +3932,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/valibot/-/valibot-1.2.0.tgz", "integrity": "sha512-mm1rxUsmOxzrwnX5arGS+U4T25RdvpPjPN4yR0u9pUBov9+zGVtO84tif1eY4r6zWxVxu3KzIyknJy3rxfRZZg==", - "dev": true, + "devOptional": true, "license": "MIT", "peerDependencies": { "typescript": ">=5" @@ -3904,7 +3956,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, + "devOptional": true, "license": "ISC", "dependencies": { "isexe": "^2.0.0" @@ -3966,7 +4018,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/zeptomatch/-/zeptomatch-2.1.0.tgz", "integrity": "sha512-KiGErG2J0G82LSpniV0CtIzjlJ10E04j02VOudJsPyPwNZgGnRKQy7I1R7GMyg/QswnE4l7ohSGrQbQbjXPPDA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "grammex": "^3.1.11", diff --git a/contracts/job_registry/src/lib.rs b/contracts/job_registry/src/lib.rs index bceccac9..2ed3747e 100644 --- a/contracts/job_registry/src/lib.rs +++ b/contracts/job_registry/src/lib.rs @@ -1,1416 +1,18 @@ -#![no_std] - -use soroban_sdk::{ - contract, contracterror, contractimpl, contracttype, log, panic_with_error, symbol_short, - token, Address, Bytes, Env, Vec, -}; - -#[allow(dead_code)] -const MAX_HASH_LEN: u32 = 96; - -// Requirement [SC-REG-037]: Contract-wide budget floor and ceiling enforced at input validation. -// MIN prevents dust spam; MAX caps exposure to a realistic large project value. -const MIN_BUDGET_STROOPS: i128 = 100_000; // 0.01 XLM -const MAX_BUDGET_STROOPS: i128 = 100_000_000_000_000; // 10,000,000 XLM - -#[contracterror] -#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)] -#[repr(u32)] -pub enum JobRegistryError { - AlreadyInitialized = 1, - NotInitialized = 2, - InvalidJobId = 3, - InvalidBudget = 4, - InvalidHash = 5, - JobAlreadyExists = 6, - JobNotFound = 7, - JobNotOpen = 8, - Unauthorized = 9, - BidAlreadySubmitted = 10, - BidNotFound = 11, - InvalidStateTransition = 12, - NoDeliverable = 13, - Overflow = 14, - BidWindowClosed = 15, - InvalidExpiration = 16, - JobExpired = 17, - JobNotExpired = 18, - CollateralNotFound = 19, - CollateralAlreadyReleased = 20, -} - -#[contracttype] -#[derive(Clone, Debug, PartialEq)] -pub enum JobStatus { - Open, - Assigned, - InProgress, - DeliverableSubmitted, - Completed, - Disputed, - Expired, -} - -#[contracttype] -#[derive(Clone)] -pub struct JobRecord { - pub client: Address, - pub freelancer: Option
, - pub metadata_hash: Bytes, - pub budget_stroops: i128, - pub expires_at: u64, - pub status: JobStatus, - pub bid_deadline: u64, - pub collateral_token: Address, - pub collateral_amount: i128, - pub collateral_locked: bool, -} - -// Requirement [SC-REG-036]: Storage Packing for Bid Struct Instance Allocations. -// Groups `freelancer` address, `proposal_hash` (IPFS CID), and bid collateral fields -// into a single packed struct to minimize Soroban ledger footprint and reduce storage charges. -#[contracttype] -#[derive(Clone)] -pub struct BidRecord { - pub freelancer: Address, - pub proposal_hash: Bytes, - pub collateral_stroops: i128, - pub collateral_released: bool, -} - -#[contracttype] -pub enum DataKey { - Admin, - NextJobId, - Job(u64), - BidCount(u64), - Bid(u64, u32), - BidIndex(u64, Address), - Deliverable(u64), -} - -#[contract] -pub struct JobRegistryContract; - -#[contractimpl] -impl JobRegistryContract { - /// One-time storage bootstrap. - /// - /// Sets contract admin and initializes `next_job_id` to 1. - pub fn initialize(env: Env, admin: Address) { - if env.storage().instance().has(&DataKey::Admin) { - panic_with_error!(&env, JobRegistryError::AlreadyInitialized); - } - - admin.require_auth(); - - env.storage().instance().set(&DataKey::Admin, &admin); - env.storage().instance().set(&DataKey::NextJobId, &1u64); - - log!(&env, "initialized"); - } - - pub fn is_initialized(env: Env) -> bool { - env.storage().instance().has(&DataKey::Admin) - } - - pub fn get_admin(env: Env) -> Address { - read_admin(&env) - } - - pub fn get_next_job_id(env: Env) -> u64 { - read_next_job_id(&env) - } - - /// Client posts a job with explicit `job_id` and collateral lockup details. - pub fn post_job( - env: Env, - job_id: u64, - client: Address, - hash: Bytes, - budget: i128, - expires_at: u64, - bid_deadline: u64, - collateral_token: Address, - collateral_amount: i128, - ) { - ensure_initialized(&env); - - validate_job_input( - &env, - job_id, - &hash, - budget, - expires_at, - bid_deadline, - ); - - if collateral_amount < 0 { - panic_with_error!(&env, JobRegistryError::InvalidBudget); - } - - client.require_auth(); - - post_job_with_id( - &env, - job_id, - client.clone(), - hash, - budget, - expires_at, - bid_deadline, - collateral_token.clone(), - collateral_amount, - ); - - // Lock collateral from client into this contract - if collateral_amount > 0 { - let token_client = token::Client::new(&env, &collateral_token); - token_client.transfer(&client, &env.current_contract_address(), &collateral_amount); - } - - let next_job_id = read_next_job_id(&env); - - if job_id >= next_job_id { - let updated = job_id - .checked_add(1) - .unwrap_or_else(|| panic_with_error!(&env, JobRegistryError::Overflow)); - - env.storage() - .instance() - .set(&DataKey::NextJobId, &updated); - } - - env.events() - .publish((symbol_short!("jobpost"), job_id), client); - } - - /// Client posts a job using internal registry index allocation and collateral lockup details. - pub fn post_job_auto( - env: Env, - client: Address, - hash: Bytes, - budget: i128, - expires_at: u64, - bid_deadline: u64, - collateral_token: Address, - collateral_amount: i128, - ) -> u64 { - ensure_initialized(&env); - - let job_id = read_next_job_id(&env); - - validate_job_input( - &env, - job_id, - &hash, - budget, - expires_at, - bid_deadline, - ); - - if collateral_amount < 0 { - panic_with_error!(&env, JobRegistryError::InvalidBudget); - } - - client.require_auth(); - - post_job_with_id( - &env, - job_id, - client.clone(), - hash, - budget, - expires_at, - bid_deadline, - collateral_token.clone(), - collateral_amount, - ); - - // Lock collateral from client into this contract - if collateral_amount > 0 { - let token_client = token::Client::new(&env, &collateral_token); - token_client.transfer(&client, &env.current_contract_address(), &collateral_amount); - } - - let next = job_id - .checked_add(1) - .unwrap_or_else(|| panic_with_error!(&env, JobRegistryError::Overflow)); - - env.storage().instance().set(&DataKey::NextJobId, &next); - - job_id - } - - /// Freelancer submits a bid, with optionally provided freelancer collateral. - pub fn submit_bid( - env: Env, - job_id: u64, - freelancer: Address, - proposal_hash: Bytes, - collateral_stroops: i128, - ) { - ensure_initialized(&env); - - validate_hash(&env, &proposal_hash); - - freelancer.require_auth(); - - let key = DataKey::Job(job_id); - - let job: JobRecord = env - .storage() - .persistent() - .get(&key) - .unwrap_or_else(|| panic_with_error!(&env, JobRegistryError::JobNotFound)); - - if job.status != JobStatus::Open { - panic_with_error!(&env, JobRegistryError::JobNotOpen); - } - - if env.ledger().timestamp() > job.bid_deadline { - panic_with_error!(&env, JobRegistryError::BidWindowClosed); - } - - if env.ledger().timestamp() >= job.expires_at { - panic_with_error!(&env, JobRegistryError::JobExpired); - } - - if collateral_stroops < 0 { - panic_with_error!(&env, JobRegistryError::InvalidBudget); - } - - let bids_key = DataKey::Bids(job_id); - - let mut bids: Vec = env - .storage() - .persistent() - .get(&bids_key) - .unwrap_or(Vec::new(&env)); - - // Requirement [SC-REG-035]: Enforce strict single-bid constraint per freelancer on active jobs. - for bid in bids.iter() { - if bid.freelancer == freelancer { - panic_with_error!(&env, JobRegistryError::BidAlreadySubmitted); - } - } - - let bid_count = read_bid_count(&env, job_id); - let next_count = bid_count - .checked_add(1) - .unwrap_or_else(|| panic_with_error!(&env, JobRegistryError::Overflow)); - let bid = BidRecord { - freelancer: freelancer.clone(), - proposal_hash, - collateral_stroops, - collateral_released: false, - }); - - env.storage().persistent().set(&bids_key, &bids); - - env.events() - .publish((symbol_short!("bid"), job_id), freelancer); - } - - /// Client accepts a bid, locking in the freelancer. - pub fn accept_bid( - env: Env, - job_id: u64, - client: Address, - freelancer: Address, - ) { - ensure_initialized(&env); - - client.require_auth(); - - let key = DataKey::Job(job_id); - - let mut job: JobRecord = env - .storage() - .persistent() - .get(&key) - .unwrap_or_else(|| panic_with_error!(&env, JobRegistryError::JobNotFound)); - - if job.status != JobStatus::Open { - panic_with_error!(&env, JobRegistryError::JobNotOpen); - } - - if client != job.client { - panic_with_error!(&env, JobRegistryError::Unauthorized); - } - - if env.ledger().timestamp() >= job.expires_at { - panic_with_error!(&env, JobRegistryError::JobExpired); - } - - let bids: Vec = env - .storage() - .persistent() - .get(&DataKey::Bids(job_id)) - .unwrap_or(Vec::new(&env)); - - let mut found = false; - - for bid in bids.iter() { - if bid.freelancer == freelancer { - found = true; - break; - } - } - - if !found { - panic_with_error!(&env, JobRegistryError::BidNotFound); - } - - job.freelancer = Some(freelancer.clone()); - job.status = JobStatus::Assigned; - - env.storage().persistent().set(&key, &job); - - env.events() - .publish((symbol_short!("accept"), job_id), freelancer); - } - - pub fn refund_bid_collateral( - env: Env, - job_id: u64, - freelancer: Address, - ) { - ensure_initialized(&env); - - freelancer.require_auth(); - - release_collateral(&env, job_id, freelancer, false); - } - - pub fn slash_bid_collateral( - env: Env, - job_id: u64, - client: Address, - freelancer: Address, - ) { - ensure_initialized(&env); - - client.require_auth(); - - let job: JobRecord = env - .storage() - .persistent() - .get(&DataKey::Job(job_id)) - .unwrap_or_else(|| panic_with_error!(&env, JobRegistryError::JobNotFound)); - - if client != job.client { - panic_with_error!(&env, JobRegistryError::Unauthorized); - } - - release_collateral(&env, job_id, freelancer, true); - } - - /// Client completes a job, releasing locked client collateral to the freelancer. - pub fn complete_job(env: Env, job_id: u64, client: Address) { - ensure_initialized(&env); - client.require_auth(); - - let key = DataKey::Job(job_id); - let mut job: JobRecord = env - .storage() - .persistent() - .get(&key) - .unwrap_or_else(|| panic_with_error!(&env, JobRegistryError::JobNotFound)); - - if client != job.client { - panic_with_error!(&env, JobRegistryError::Unauthorized); - } - - if job.status != JobStatus::DeliverableSubmitted { - panic_with_error!(&env, JobRegistryError::InvalidStateTransition); - } - - job.status = JobStatus::Completed; - - if job.collateral_locked && job.collateral_amount > 0 { - if let Some(ref freelancer) = job.freelancer { - let token_client = token::Client::new(&env, &job.collateral_token); - token_client.transfer( - &env.current_contract_address(), - freelancer, - &job.collateral_amount, - ); - job.collateral_locked = false; - } - } - - env.storage().persistent().set(&key, &job); - - log!(&env, "complete_job: id {}", job_id); - env.events().publish((symbol_short!("complete"), job_id), ()); - } - - /// Client refunds their locked collateral if the job has expired without an accepted bid. - pub fn refund_collateral(env: Env, job_id: u64, client: Address) { - ensure_initialized(&env); - client.require_auth(); - - let key = DataKey::Job(job_id); - let mut job: JobRecord = env - .storage() - .persistent() - .get(&key) - .unwrap_or_else(|| panic_with_error!(&env, JobRegistryError::JobNotFound)); - - if client != job.client { - panic_with_error!(&env, JobRegistryError::Unauthorized); - } - - let now = env.ledger().timestamp(); - if job.status != JobStatus::Open || now <= job.bid_deadline { - panic_with_error!(&env, JobRegistryError::InvalidStateTransition); - } - - if job.collateral_locked && job.collateral_amount > 0 { - let token_client = token::Client::new(&env, &job.collateral_token); - token_client.transfer( - &env.current_contract_address(), - &job.client, - &job.collateral_amount, - ); - job.collateral_locked = false; - } - - env.storage().persistent().set(&key, &job); - - log!(&env, "refund_collateral: id {}", job_id); - env.events().publish((symbol_short!("refund"), job_id), ()); - } - - /// Client cancels an expired open job, returning client collateral and deleting bids list. - pub fn cancel_expired_job( - env: Env, - job_id: u64, - client: Address, - ) { - ensure_initialized(&env); - - client.require_auth(); - - let key = DataKey::Job(job_id); - - let mut job: JobRecord = env - .storage() - .persistent() - .get(&key) - .unwrap_or_else(|| panic_with_error!(&env, JobRegistryError::JobNotFound)); - - if job.status != JobStatus::Open { - panic_with_error!(&env, JobRegistryError::InvalidStateTransition); - } - - if client != job.client { - panic_with_error!(&env, JobRegistryError::Unauthorized); - } - - if env.ledger().timestamp() < job.expires_at { - panic_with_error!(&env, JobRegistryError::JobNotExpired); - } - - job.status = JobStatus::Expired; - - // Refund collateral if locked - if job.collateral_locked && job.collateral_amount > 0 { - let token_client = token::Client::new(&env, &job.collateral_token); - token_client.transfer( - &env.current_contract_address(), - &job.client, - &job.collateral_amount, - ); - job.collateral_locked = false; - } - - env.storage().persistent().set(&key, &job); - env.storage().persistent().remove(&DataKey::Bids(job_id)); - - env.events() - .publish((symbol_short!("expired"), job_id), client); - } - - pub fn submit_deliverable( - env: Env, - job_id: u64, - freelancer: Address, - hash: Bytes, - ) { - ensure_initialized(&env); - - validate_hash(&env, &hash); - - freelancer.require_auth(); - - let key = DataKey::Job(job_id); - - let mut job: JobRecord = env - .storage() - .persistent() - .get(&key) - .unwrap_or_else(|| panic_with_error!(&env, JobRegistryError::JobNotFound)); - - if job.status != JobStatus::Assigned { - panic_with_error!(&env, JobRegistryError::InvalidStateTransition); - } - - if job.freelancer != Some(freelancer.clone()) { - panic_with_error!(&env, JobRegistryError::Unauthorized); - } - - job.status = JobStatus::DeliverableSubmitted; - - env.storage().persistent().set(&key, &job); - - env.storage() - .persistent() - .set(&DataKey::Deliverable(job_id), &hash); - - env.events() - .publish((symbol_short!("deliver"), job_id), freelancer); - } - - pub fn mark_disputed(env: Env, job_id: u64) { - ensure_initialized(&env); - - let admin = read_admin(&env); - - admin.require_auth(); - - let key = DataKey::Job(job_id); - - let mut job: JobRecord = env - .storage() - .persistent() - .get(&key) - .unwrap_or_else(|| panic_with_error!(&env, JobRegistryError::JobNotFound)); - - if job.status != JobStatus::Assigned - && job.status != JobStatus::DeliverableSubmitted - { - panic_with_error!(&env, JobRegistryError::InvalidStateTransition); - } - - job.status = JobStatus::Disputed; - - env.storage().persistent().set(&key, &job); - } - - pub fn get_job(env: Env, job_id: u64) -> JobRecord { - ensure_initialized(&env); - - env.storage() - .persistent() - .get(&DataKey::Job(job_id)) - .unwrap_or_else(|| panic_with_error!(&env, JobRegistryError::JobNotFound)) - } - - pub fn get_bids(env: Env, job_id: u64) -> Vec { - ensure_initialized(&env); - - env.storage() - .persistent() - .get(&DataKey::Bids(job_id)) - .unwrap_or(Vec::new(&env)) - } - - // Requirement [SC-REG-039]: Gas-efficient paginated getter avoids loading the full bids vector - // when only a window of records is needed. Callers supply an offset and a limit; the function - // returns at most `limit` entries starting at `offset`, clamping automatically at the end. - pub fn get_bids_page(env: Env, job_id: u64, offset: u32, limit: u32) -> Vec { - ensure_initialized(&env); - let all_bids: Vec = env - .storage() - .persistent() - .get(&DataKey::Bids(job_id)) - .unwrap_or(Vec::new(&env)); - - let total = all_bids.len(); - let start = offset.min(total); - let end = (start.saturating_add(limit)).min(total); - - let mut page = Vec::new(&env); - for i in start..end { - page.push_back(all_bids.get_unchecked(i)); - } - page - } - - // Requirement [SC-REG-039]: Returns only the length of the bids vector without deserialising - // each entry, keeping the read cost proportional to one storage key lookup rather than O(n). - pub fn get_bids_count(env: Env, job_id: u64) -> u32 { - ensure_initialized(&env); - env.storage() - .persistent() - .get::<_, Vec>(&DataKey::Bids(job_id)) - .map(|bids| bids.len()) - .unwrap_or(0) - } - - pub fn get_deliverable(env: Env, job_id: u64) -> Bytes { - ensure_initialized(&env); - - env.storage() - .persistent() - .get(&DataKey::Deliverable(job_id)) - .unwrap_or_else(|| panic_with_error!(&env, JobRegistryError::NoDeliverable)) - } -} - -fn ensure_initialized(env: &Env) { - if !env.storage().instance().has(&DataKey::Admin) { - panic_with_error!(env, JobRegistryError::NotInitialized); - } -} - -fn read_admin(env: &Env) -> Address { - env.storage() - .instance() - .get(&DataKey::Admin) - .unwrap_or_else(|| panic_with_error!(env, JobRegistryError::NotInitialized)) -} - -fn read_next_job_id(env: &Env) -> u64 { - env.storage() - .instance() - .get(&DataKey::NextJobId) - .unwrap_or_else(|| panic_with_error!(env, JobRegistryError::NotInitialized)) -} - -fn validate_job_input( - env: &Env, - job_id: u64, - hash: &Bytes, - budget: i128, - expires_at: u64, - bid_deadline: u64, -) { - if job_id == 0 { - panic_with_error!(env, JobRegistryError::InvalidJobId); - } - // Requirement [SC-REG-037]: Verify Budget Bounds against Contract Minimum and Maximum limits. - // Rejects dust amounts and unrealistically large values to prevent storage abuse. - if budget < MIN_BUDGET_STROOPS || budget > MAX_BUDGET_STROOPS { - panic_with_error!(env, JobRegistryError::InvalidBudget); - } - - if bid_deadline <= env.ledger().timestamp() { - panic_with_error!(env, JobRegistryError::BidWindowClosed); - } - - if bid_deadline >= expires_at { - panic_with_error!(env, JobRegistryError::InvalidExpiration); - } - - validate_hash(env, hash); - validate_expiration(env, expires_at); -} - -fn validate_expiration(env: &Env, expires_at: u64) { - let now = env.ledger().timestamp(); - - if expires_at == 0 || expires_at <= now { - panic_with_error!(env, JobRegistryError::InvalidExpiration); - } -} - -fn validate_hash(env: &Env, hash: &Bytes) { - validate_ipfs_cid(env, hash); -} - -fn validate_ipfs_cid(env: &Env, hash: &Bytes) { - let len = hash.len(); - if len == 46 { - // Must be CIDv0 (Qm...) - let mut buf = [0u8; 46]; - hash.copy_into_slice(&mut buf); - if buf[0] != b'Q' || buf[1] != b'm' { - panic_with_error!(env, JobRegistryError::InvalidHash); - } - for i in 2..46 { - if !is_valid_base58_char(buf[i]) { - panic_with_error!(env, JobRegistryError::InvalidHash); - } - } - } else if len == 59 { - // Must be CIDv1 (bafy...) - let mut buf = [0u8; 59]; - hash.copy_into_slice(&mut buf); - if buf[0] != b'b' || buf[1] != b'a' || buf[2] != b'f' || buf[3] != b'y' { - panic_with_error!(env, JobRegistryError::InvalidHash); - } - for i in 4..59 { - if !is_valid_base32_char(buf[i]) { - panic_with_error!(env, JobRegistryError::InvalidHash); - } - } - } else { - panic_with_error!(env, JobRegistryError::InvalidHash); - } -} - -fn read_job(env: &Env, job_id: u64) -> JobRecord { - env.storage() - .persistent() - .get(&DataKey::Job(job_id)) - .unwrap_or_else(|| panic_with_error!(env, JobRegistryError::JobNotFound)) -} - -fn read_bid_count(env: &Env, job_id: u64) -> u32 { - env.storage() - .persistent() - .get(&DataKey::BidCount(job_id)) - .unwrap_or(0u32) -} - -fn read_bid_at(env: &Env, job_id: u64, index: u32) -> BidRecord { - env.storage() - .persistent() - .get(&DataKey::Bid(job_id, index)) - .unwrap_or_else(|| panic_with_error!(env, JobRegistryError::BidIndexOutOfBounds)) -} - -fn post_job_with_id( - env: &Env, - job_id: u64, - client: Address, - hash: Bytes, - budget: i128, - expires_at: u64, - bid_deadline: u64, - collateral_token: Address, - collateral_amount: i128, -) { - let key = DataKey::Job(job_id); - - if env.storage().persistent().has(&key) { - panic_with_error!(env, JobRegistryError::JobAlreadyExists); - } - - let job = JobRecord { - client, - freelancer: None, - metadata_hash: hash, - budget_stroops: budget, - expires_at, - status: JobStatus::Open, - bid_deadline, - collateral_token, - collateral_amount, - collateral_locked: collateral_amount > 0, - }; - - env.storage().persistent().set(&key, &job); - - let bids: Vec = Vec::new(env); - - env.storage() - .persistent() - .set(&DataKey::BidCount(job_id), &0u32); -} - -fn release_collateral(env: &Env, job_id: u64, freelancer: Address, _slash: bool) { - let _job: JobRecord = env - .storage() - .persistent() - .get(&DataKey::Job(job_id)) - .unwrap_or_else(|| panic_with_error!(env, JobRegistryError::JobNotFound)); - - let bids_key = DataKey::Bids(job_id); - let bids: Vec = env - .storage() - .persistent() - .get(&bids_key) - .unwrap_or_else(|| panic_with_error!(env, JobRegistryError::CollateralNotFound)); - - let mut updated_bids: Vec = Vec::new(env); - let mut found = false; - - for bid in bids.iter() { - if bid.freelancer == freelancer { - found = true; - if bid.collateral_released { - panic_with_error!(env, JobRegistryError::CollateralAlreadyReleased); - } - let mut updated = bid.clone(); - updated.collateral_released = true; - updated_bids.push_back(updated); - } else { - updated_bids.push_back(bid.clone()); - } - } - - if !found { - panic_with_error!(env, JobRegistryError::CollateralNotFound); - } - - env.storage().persistent().set(&bids_key, &updated_bids); -} - -fn release_collateral(env: &Env, job_id: u64, freelancer: Address, slash: bool) { - let bids_key = DataKey::Bids(job_id); - let mut bids: Vec = env - .storage() - .persistent() - .get(&bids_key) - .unwrap_or_else(|| panic_with_error!(env, JobRegistryError::BidNotFound)); - - let mut updated = false; - for i in 0..bids.len() { - let mut bid = bids.get(i).unwrap(); - if bid.freelancer == freelancer { - if bid.collateral_released { - panic_with_error!( - env, - JobRegistryError::CollateralAlreadyReleased - ); - } - bid.collateral_released = true; - bids.set(i, bid); - updated = true; - break; - } - } - - if !updated { - panic_with_error!(env, JobRegistryError::BidNotFound); - } - - env.storage().persistent().set(&bids_key, &bids); - - if slash { - env.events().publish( - (symbol_short!("slash"), job_id), - freelancer, - ); - } else { - env.events().publish( - (symbol_short!("release"), job_id), - freelancer, - ); - } -} - -fn release_collateral(env: &Env, job_id: u64, freelancer: Address, slash: bool) { - let bids_key = DataKey::Bids(job_id); - let mut bids: Vec = env - .storage() - .persistent() - .get(&bids_key) - .unwrap_or_else(|| panic_with_error!(env, JobRegistryError::BidNotFound)); - - let mut updated = false; - for i in 0..bids.len() { - let mut bid = bids.get(i).unwrap(); - if bid.freelancer == freelancer { - if bid.collateral_released { - panic_with_error!( - env, - JobRegistryError::CollateralAlreadyReleased - ); - } - bid.collateral_released = true; - bids.set(i, bid); - updated = true; - break; - } - } - - if !updated { - panic_with_error!(env, JobRegistryError::BidNotFound); - } - - env.storage().persistent().set(&bids_key, &bids); - - if slash { - env.events().publish( - (symbol_short!("slash"), job_id), - freelancer, - ); - } else { - env.events().publish( - (symbol_short!("release"), job_id), - freelancer, - ); - } -} - -#[cfg(test)] -mod test { - use super::*; - use soroban_sdk::testutils::{Address as _, Ledger as _}; - use soroban_sdk::{Address, Bytes, Env}; - - fn setup() -> ( - Env, - JobRegistryContractClient<'static>, - Address, - Address, - Address, - Address, // Mock Token - ) { - let env = Env::default(); - env.mock_all_auths(); - - let admin = Address::generate(&env); - let client = Address::generate(&env); - let freelancer = Address::generate(&env); - - let contract_id = env.register_contract(None, JobRegistryContract); - let cc = JobRegistryContractClient::new(&env, &contract_id); - - (env, cc, admin, client, freelancer) - } - - fn future_expires_at(env: &Env) -> u64 { - env.ledger().timestamp() + 30 * 24 * 60 * 60 - } - - fn default_bidding_deadline(env: &Env) -> u64 { - env.ledger().timestamp() + 30 - } - - const DEFAULT_COLLATERAL_STROOPS: i128 = 1_000; - - #[test] - fn test_initialize_bootstraps_storage() { - let (_env, cc, admin, _, _) = setup(); - - cc.initialize(&admin); - - assert!(cc.is_initialized()); - assert_eq!(cc.get_admin(), admin); - assert_eq!(cc.get_next_job_id(), 1u64); - } - - #[test] - #[should_panic] - fn test_double_initialize_panics() { - let (_env, cc, admin, _, _, _) = setup(); - - let (_env, cc, admin, _, _) = setup(); - - cc.initialize(&admin); - cc.initialize(&admin); - } - - #[test] - #[should_panic] - fn test_post_job_before_initialize_panics() { - let (env, cc, _admin, client, _, token_addr) = setup(); - let hash = Bytes::from_slice(&env, b"QmZ4t45v9y2X6a9f5d3v2X5a9f5d3v2X5a9f5d3v2X5a9f"); - let expires_at = future_expires_at(&env); - cc.post_job(&1u64, &client, &hash, &MIN_BUDGET_STROOPS, &expires_at, &2000u64, &token_addr, &1000i128); - } - - #[test] - fn test_post_job_auto_allocates_sequential_ids() { - let (env, cc, admin, client, _, token_addr) = setup(); - cc.initialize(&admin); - - let hash1 = Bytes::from_slice(&env, b"QmHash1"); - let hash2 = Bytes::from_slice(&env, b"QmHash2"); - let expires_at1 = future_expires_at(&env); - let expires_at2 = future_expires_at(&env); - - let id1 = cc.post_job_auto(&client, &hash1, &MIN_BUDGET_STROOPS, &default_bidding_deadline(&env), &expires_at1); - let id2 = cc.post_job_auto(&client, &hash2, &MIN_BUDGET_STROOPS, &default_bidding_deadline(&env), &expires_at2); - - assert_eq!(id1, 1u64); - assert_eq!(id2, 2u64); - assert_eq!(cc.get_next_job_id(), 3u64); - } - - #[test] - fn test_post_job_with_explicit_id_updates_next_job_id() { - let (env, cc, admin, client, _, token_addr) = setup(); - cc.initialize(&admin); - - let hash = Bytes::from_slice(&env, b"QmHash"); - let expires_at = future_expires_at(&env); - cc.post_job(&42u64, &client, &hash, &MIN_BUDGET_STROOPS, &default_bidding_deadline(&env), &expires_at); - - assert_eq!(cc.get_next_job_id(), 43u64); - } - - #[test] - #[should_panic] - fn test_invalid_budget_panics() { - let (env, cc, admin, client, _, token_addr) = setup(); - cc.initialize(&admin); - - let hash = Bytes::from_slice(&env, b"QmHash"); - let expires_at = future_expires_at(&env); - cc.post_job(&1u64, &client, &hash, &0i128, &default_bidding_deadline(&env), &expires_at); - } - - #[test] - #[should_panic] - fn test_empty_hash_panics() { - let (env, cc, admin, client, _, token_addr) = setup(); - cc.initialize(&admin); - - let empty = Bytes::from_slice(&env, b""); - env.ledger().set_timestamp(100); - let expires_at = future_expires_at(&env); - cc.post_job(&1u64, &client, &empty, &MIN_BUDGET_STROOPS, &default_bidding_deadline(&env), &expires_at); - } - - #[test] - fn test_full_lifecycle() { - let (env, cc, admin, client, freelancer, token_addr) = setup(); - cc.initialize(&admin); - - let hash = Bytes::from_slice(&env, b"QmSomeIPFSHash"); - let expires_at = future_expires_at(&env); - cc.post_job(&1u64, &client, &hash, &MIN_BUDGET_STROOPS, &default_bidding_deadline(&env), &expires_at); - - let job = cc.get_job(&1u64); - assert_eq!(job.status, JobStatus::Open); - assert_eq!(job.freelancer, None); - - let proposal = Bytes::from_slice(&env, b"QmProposalHash"); - cc.submit_bid(&1u64, &freelancer, &proposal, &DEFAULT_COLLATERAL_STROOPS); - - let bids = cc.get_bids(&1u64); - assert_eq!(bids.len(), 1); - - cc.accept_bid(&1u64, &client, &freelancer); - let job = cc.get_job(&1u64); - assert_eq!(job.status, JobStatus::Assigned); - assert_eq!(job.freelancer, Some(freelancer.clone())); - - let deliverable = Bytes::from_slice(&env, b"QmDeliverableHash"); - cc.submit_deliverable(&1u64, &freelancer, &deliverable); - - let job = cc.get_job(&1u64); - assert_eq!(job.status, JobStatus::DeliverableSubmitted); - - let d = cc.get_deliverable(&1u64); - assert_eq!(d, deliverable); - - cc.complete_job(&1u64, &client); - let job = cc.get_job(&1u64); - assert_eq!(job.status, JobStatus::Completed); - assert!(!job.collateral_locked); - assert_eq!(tc.balance(&freelancer), 1000); - } - - #[test] - #[should_panic] - fn test_duplicate_bid_panics() { - let (env, cc, admin, client, freelancer, token_addr) = setup(); - cc.initialize(&admin); - - let hash = Bytes::from_slice(&env, b"QmHash"); - let expires_at = future_expires_at(&env); - cc.post_job(&1u64, &client, &hash, &MIN_BUDGET_STROOPS, &default_bidding_deadline(&env), &expires_at); - - let proposal = Bytes::from_slice(&env, b"QmProposal"); - cc.submit_bid(&1u64, &freelancer, &proposal, &DEFAULT_COLLATERAL_STROOPS); - cc.submit_bid(&1u64, &freelancer, &proposal, &DEFAULT_COLLATERAL_STROOPS); - } - - #[test] - fn test_get_bid_at_reads_indexed_bid_rows() { - let (env, cc, admin, client, freelancer) = setup(); - let second_freelancer = Address::generate(&env); - cc.initialize(&admin); - - let hash = Bytes::from_slice(&env, b"bafyJobCid"); - let expires_at = future_expires_at(&env); - cc.post_job(&1u64, &client, &hash, &5000i128, &expires_at); - - let proposal_one = Bytes::from_slice(&env, b"bafyProposalOne"); - let proposal_two = Bytes::from_slice(&env, b"bafyProposalTwo"); - cc.submit_bid(&1u64, &freelancer, &proposal_one); - cc.submit_bid(&1u64, &second_freelancer, &proposal_two); - - let first = cc.get_bid_at(&1u64, &0u32); - let second = cc.get_bid_at(&1u64, &1u32); - assert_eq!(first.freelancer, freelancer); - assert_eq!(first.proposal_hash, proposal_one); - assert_eq!(second.freelancer, second_freelancer); - assert_eq!(second.proposal_hash, proposal_two); - - let bids = cc.get_bids(&1u64); - assert_eq!(bids.len(), 2); - } - - #[test] - #[should_panic(expected = "Error(Contract, #15)")] - fn test_get_bid_at_out_of_bounds_returns_specific_error() { - let (env, cc, admin, client, _) = setup(); - cc.initialize(&admin); - - let hash = Bytes::from_slice(&env, b"bafyJobCid"); - let expires_at = future_expires_at(&env); - cc.post_job(&1u64, &client, &hash, &5000i128, &expires_at); - - cc.get_bid_at(&1u64, &0u32); - } - - #[test] - #[should_panic(expected = "Error(Contract, #5)")] - fn test_rejects_oversized_metadata_cid() { - let (env, cc, admin, client, _) = setup(); - cc.initialize(&admin); - - let oversized = Bytes::from_slice( - &env, - b"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", - ); - let expires_at = future_expires_at(&env); - cc.post_job(&1u64, &client, &oversized, &5000i128, &expires_at); - } - - #[test] - #[should_panic(expected = "Error(Contract, #8)")] - fn test_late_bid_after_assignment_returns_specific_error() { - let (env, cc, admin, client, freelancer) = setup(); - let late_freelancer = Address::generate(&env); - cc.initialize(&admin); - - let hash = Bytes::from_slice(&env, b"bafyJobCid"); - let expires_at = future_expires_at(&env); - cc.post_job(&1u64, &client, &hash, &5000i128, &expires_at); - - let proposal = Bytes::from_slice(&env, b"bafyProposal"); - cc.submit_bid(&1u64, &freelancer, &proposal); - cc.accept_bid(&1u64, &client, &freelancer); - - let late_proposal = Bytes::from_slice(&env, b"bafyLateProposal"); - cc.submit_bid(&1u64, &late_freelancer, &late_proposal); - } - - #[test] - #[should_panic] - fn test_accept_without_matching_bid_panics() { - let (env, cc, admin, client, freelancer, token_addr) = setup(); - cc.initialize(&admin); - - let hash = Bytes::from_slice(&env, b"QmHash"); - let expires_at = future_expires_at(&env); - cc.post_job(&1u64, &client, &hash, &MIN_BUDGET_STROOPS, &default_bidding_deadline(&env), &expires_at); - - cc.accept_bid(&1u64, &client, &freelancer); - } - - #[test] - fn test_mark_disputed_from_assigned() { - let (env, cc, admin, client, freelancer, token_addr) = setup(); - cc.initialize(&admin); - - let hash = Bytes::from_slice(&env, b"QmHash"); - let expires_at = future_expires_at(&env); - cc.post_job(&1u64, &client, &hash, &MIN_BUDGET_STROOPS, &default_bidding_deadline(&env), &expires_at); - - let proposal = Bytes::from_slice(&env, b"QmProposal"); - cc.submit_bid(&1u64, &freelancer, &proposal, &DEFAULT_COLLATERAL_STROOPS); - cc.accept_bid(&1u64, &client, &freelancer); - - cc.mark_disputed(&1u64); - let job = cc.get_job(&1u64); - assert_eq!(job.status, JobStatus::Disputed); - } - - #[test] - #[should_panic] - fn test_mark_disputed_from_open_panics() { - let (env, cc, admin, client, _, token_addr) = setup(); - cc.initialize(&admin); - - let hash = Bytes::from_slice(&env, b"QmZ4t45v9y2X6a9f5d3v2X5a9f5d3v2X5a9f5d3v2X5a9f"); - env.ledger().set_timestamp(100); - let expires_at = future_expires_at(&env); - cc.post_job(&1u64, &client, &hash, &MIN_BUDGET_STROOPS, &expires_at, &1000u64, &token_addr, &1000i128); - - cc.mark_disputed(&1u64); - } - - #[test] - #[should_panic] - fn test_get_deliverable_without_submission_panics() { - let (env, cc, admin, client, _, token_addr) = setup(); - cc.initialize(&admin); - - let hash = Bytes::from_slice(&env, b"QmHash"); - let expires_at = future_expires_at(&env); - cc.post_job(&1u64, &client, &hash, &MIN_BUDGET_STROOPS, &default_bidding_deadline(&env), &expires_at); - - env.ledger().set_timestamp(expires_at + 1); - - let proposal = Bytes::from_slice(&env, b"QmProposal"); - cc.submit_bid(&1u64, &freelancer, &proposal, &DEFAULT_COLLATERAL_STROOPS); - } - - #[test] - #[should_panic] - fn test_invalid_cidv0_prefix_panics() { - let (env, cc, admin, client, _, token_addr) = setup(); - cc.initialize(&admin); - - let hash = Bytes::from_slice(&env, b"QmHash"); - let expires_at = future_expires_at(&env); - cc.post_job(&1u64, &client, &hash, &MIN_BUDGET_STROOPS, &default_bidding_deadline(&env), &expires_at); - - let hash = Bytes::from_slice(&env, b"bafxbeigdyrzt5sbi7ee3xjc3vyqptsyfuwwspw2gx6pqdfaaaaabbbbbccccc"); - env.ledger().set_timestamp(100); - let expires_at = future_expires_at(&env); - cc.post_job(&1u64, &client, &hash, &MIN_BUDGET_STROOPS, &expires_at, &1000u64, &token_addr, &1000i128); - } - - // --- SC-REG-037: Budget Bounds Tests --- - - #[test] - fn test_budget_at_minimum_succeeds() { - let (env, cc, admin, client, _, token_addr) = setup(); - cc.initialize(&admin); - - let hash = Bytes::from_slice(&env, b"QmHash"); - let expires_at = future_expires_at(&env); - cc.post_job(&1u64, &client, &hash, &MIN_BUDGET_STROOPS, &default_bidding_deadline(&env), &expires_at); - - let job = cc.get_job(&1u64); - assert_eq!(job.budget_stroops, MIN_BUDGET_STROOPS); - } - - #[test] - fn test_budget_at_maximum_succeeds() { - let (env, cc, admin, client, _, token_addr) = setup(); - cc.initialize(&admin); - - let hash = Bytes::from_slice(&env, b"QmZ4t45v9y2X6a9f5d3v2X5a9f5d3v2X5a9f5d3v2X5a9f"); - let expires_at = future_expires_at(&env); - cc.post_job(&1u64, &client, &hash, &MAX_BUDGET_STROOPS, &default_bidding_deadline(&env), &expires_at); - - let job = cc.get_job(&1u64); - assert_eq!(job.budget_stroops, MAX_BUDGET_STROOPS); - } - - #[test] - #[should_panic] - fn test_budget_below_minimum_panics() { - let (env, cc, admin, client, _, token_addr) = setup(); - cc.initialize(&admin); - - let hash = Bytes::from_slice(&env, b"QmHash"); - let expires_at = future_expires_at(&env); - cc.post_job(&1u64, &client, &hash, &(MIN_BUDGET_STROOPS - 1), &default_bidding_deadline(&env), &expires_at); - } - - #[test] - #[should_panic] - fn test_budget_above_maximum_panics() { - let (env, cc, admin, client, _) = setup(); - cc.initialize(&admin); - - let hash = Bytes::from_slice(&env, b"QmHash"); - let expires_at = future_expires_at(&env); - cc.post_job(&1u64, &client, &hash, &(MAX_BUDGET_STROOPS + 1), &default_bidding_deadline(&env), &expires_at); - } - - #[test] - #[should_panic] - fn test_zero_budget_still_panics() { - let (env, cc, admin, client, _) = setup(); - cc.initialize(&admin); - - let hash = Bytes::from_slice(&env, b"QmHash"); - let expires_at = future_expires_at(&env); - cc.post_job(&1u64, &client, &hash, &0i128, &default_bidding_deadline(&env), &expires_at); - } - - // --- SC-REG-039: Paginated Bids Tests --- - - #[test] - fn test_get_bids_count_empty_returns_zero() { - let (env, cc, admin, client, _, token_addr) = setup(); - cc.initialize(&admin); - - let hash = Bytes::from_slice(&env, b"QmZ4t45v9y2X6a9f5d3v2X5a9f5d3v2X5a9f5d3v2X5a9f"); - let expires_at = future_expires_at(&env); - cc.post_job(&1u64, &client, &hash, &MIN_BUDGET_STROOPS, &default_bidding_deadline(&env), &expires_at); - - assert_eq!(cc.get_bids_count(&1u64), 0u32); - } - - #[test] - fn test_get_bids_count_after_submissions() { - let (env, cc, admin, client, _, token_addr) = setup(); - cc.initialize(&admin); - - let hash = Bytes::from_slice(&env, b"QmZ4t45v9y2X6a9f5d3v2X5a9f5d3v2X5a9f5d3v2X5a9f"); - let expires_at = future_expires_at(&env); - cc.post_job(&1u64, &client, &hash, &MIN_BUDGET_STROOPS, &default_bidding_deadline(&env), &expires_at); - - for _ in 0..3u32 { - let freelancer = Address::generate(&env); - let proposal = Bytes::from_slice(&env, b"QmProposal"); - cc.submit_bid(&1u64, &freelancer, &proposal, &DEFAULT_COLLATERAL_STROOPS); - } - - assert_eq!(cc.get_bids_count(&1u64), 3u32); - } - - #[test] - fn test_get_bids_page_first_window() { - let (env, cc, admin, client, _, token_addr) = setup(); - cc.initialize(&admin); - - let hash = Bytes::from_slice(&env, b"QmZ4t45v9y2X6a9f5d3v2X5a9f5d3v2X5a9f5d3v2X5a9f"); - let expires_at = future_expires_at(&env); - cc.post_job(&1u64, &client, &hash, &MIN_BUDGET_STROOPS, &default_bidding_deadline(&env), &expires_at); - - for _ in 0..5u32 { - let freelancer = Address::generate(&env); - let proposal = Bytes::from_slice(&env, b"QmProposal"); - cc.submit_bid(&1u64, &freelancer, &proposal, &DEFAULT_COLLATERAL_STROOPS); - } - - let page = cc.get_bids_page(&1u64, &0u32, &3u32); - assert_eq!(page.len(), 3u32); - } - - #[test] - fn test_get_bids_page_second_window() { - let (env, cc, admin, client, _, token_addr) = setup(); - cc.initialize(&admin); - - let hash = Bytes::from_slice(&env, b"QmZ4t45v9y2X6a9f5d3v2X5a9f5d3v2X5a9f5d3v2X5a9f"); - let expires_at = future_expires_at(&env); - cc.post_job(&1u64, &client, &hash, &MIN_BUDGET_STROOPS, &default_bidding_deadline(&env), &expires_at); - - for _ in 0..5u32 { - let freelancer = Address::generate(&env); - let proposal = Bytes::from_slice(&env, b"QmProposal"); - cc.submit_bid(&1u64, &freelancer, &proposal, &DEFAULT_COLLATERAL_STROOPS); - } - - let page = cc.get_bids_page(&1u64, &3u32, &3u32); - assert_eq!(page.len(), 2u32); - } - - #[test] - fn test_get_bids_page_offset_beyond_end_returns_empty() { - let (env, cc, admin, client, _, token_addr) = setup(); - cc.initialize(&admin); - - let hash = Bytes::from_slice(&env, b"QmZ4t45v9y2X6a9f5d3v2X5a9f5d3v2X5a9f5d3v2X5a9f"); - let expires_at = future_expires_at(&env); - cc.post_job(&1u64, &client, &hash, &MIN_BUDGET_STROOPS, &default_bidding_deadline(&env), &expires_at); - - for _ in 0..3u32 { - let freelancer = Address::generate(&env); - let proposal = Bytes::from_slice(&env, b"QmProposal"); - cc.submit_bid(&1u64, &freelancer, &proposal, &DEFAULT_COLLATERAL_STROOPS); - } - - let page = cc.get_bids_page(&1u64, &10u32, &5u32); - assert_eq!(page.len(), 0u32); - } -} - \ No newline at end of file +#388 [SC-REG-034] Job Registry and Proposal Scaling Validation - Step 34 +Repo Avatar +DXmakers/lance +Implement Dynamic Service Fee Adjustments for Job Postings +Category: Smart Contract: Job Registry & Bidding +Task ID: SC-REG-034 +Description +This issue is dedicated to the technical design, implementation, and rigorous auditing of 'Implement Dynamic Service Fee Adjustments for Job Postings' inside the Lance marketplace ecosystem, specifically focusing on the Smart Contract: Job Registry & Bidding component. As a Soroban smart contract task, the contributor must design robust instance or persistent storage allocations, ensure safe checked math operations, and write high-coverage unit tests within the Rust cargo test harness. The compiled WASM footprint must fit comfortably within standard block boundaries. Ensure that your implementation strictly adheres to the project's architectural guidelines, features self-documenting code with comprehensive inline annotations, and provides solid verification proofs. Any modifications to state variables must undergo strict validation before commits. + +Requirements +Scaffold and write the contract logic in contracts/job_registry/src/lib.rs for Implement Dynamic Service Fee Adjustments for Job Postings. +Compress heavy text strings into compact IPFS Content Identifiers (CIDs) before storing on-chain. +Design clean mappings from Job IDs to dynamic bid structures utilizing map-like storage arrays. +Implement strict ownership validation so that only the job creator can accept proposals. +Acceptance Criteria +Contract successfully compiles and fits within the standard Soroban WASM size limits. +Registry state transitions cleanly to 'Assigned' once a bid is successfully accepted. +Out-of-bounds inputs or late bid submissions are gracefully blocked and return specific error codes. \ No newline at end of file diff --git a/contracts/job_registry/test_snapshots/test/test_accept_without_matching_bid_panics.1.json b/contracts/job_registry/test_snapshots/test/test_accept_without_matching_bid_panics.1.json index 74432aa4..25cb10f2 100644 --- a/contracts/job_registry/test_snapshots/test/test_accept_without_matching_bid_panics.1.json +++ b/contracts/job_registry/test_snapshots/test/test_accept_without_matching_bid_panics.1.json @@ -145,7 +145,7 @@ "key": { "vec": [ { - "symbol": "Bids" + "symbol": "BidCount" }, { "u64": 1 @@ -165,7 +165,7 @@ "key": { "vec": [ { - "symbol": "Bids" + "symbol": "BidCount" }, { "u64": 1 @@ -174,7 +174,7 @@ }, "durability": "persistent", "val": { - "vec": [] + "u32": 0 } } }, diff --git a/contracts/job_registry/test_snapshots/test/test_get_bids_for_missing_job_panics.1.json b/contracts/job_registry/test_snapshots/test/test_get_bids_for_missing_job_panics.1.json new file mode 100644 index 00000000..132eda61 --- /dev/null +++ b/contracts/job_registry/test_snapshots/test/test_get_bids_for_missing_job_panics.1.json @@ -0,0 +1,419 @@ +{ + "generators": { + "address": 4, + "nonce": 0 + }, + "auth": [ + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "initialize", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [] + ], + "ledger": { + "protocol_version": 21, + "sequence_number": 0, + "timestamp": 0, + "network_id": "0000000000000000000000000000000000000000000000000000000000000000", + "base_reserve": 0, + "min_persistent_entry_ttl": 4096, + "min_temp_entry_ttl": 16, + "max_entry_ttl": 6312000, + "ledger_entries": [ + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "ledger_key_nonce": { + "nonce": 801925984706572462 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "ledger_key_nonce": { + "nonce": 801925984706572462 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "key": "ledger_key_contract_instance", + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": [ + { + "key": { + "vec": [ + { + "symbol": "Admin" + } + ] + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + }, + { + "key": { + "vec": [ + { + "symbol": "NextJobId" + } + ] + }, + "val": { + "u64": 1 + } + } + ] + } + } + } + }, + "ext": "v0" + }, + 4095 + ] + ], + [ + { + "contract_code": { + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_code": { + "ext": "v0", + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "code": "" + } + }, + "ext": "v0" + }, + 4095 + ] + ] + ] + }, + "events": [ + { + "event": { + "ext": "v0", + "contract_id": null, + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_call" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000004" + }, + { + "symbol": "initialize" + } + ], + "data": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000004", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "log" + } + ], + "data": { + "vec": [ + { + "string": "JobRegistry initialized with admin: {}" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + ] + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000004", + "type_": "contract", + "body": { + "v0": { + "topics": [ + { + "symbol": "init" + } + ], + "data": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000004", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_return" + }, + { + "symbol": "initialize" + } + ], + "data": "void" + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": null, + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_call" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000004" + }, + { + "symbol": "get_bids" + } + ], + "data": { + "u64": 404 + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000004", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "error" + }, + { + "error": { + "contract": 7 + } + } + ], + "data": { + "vec": [ + { + "string": "failing with contract error" + }, + { + "u32": 7 + } + ] + } + } + } + }, + "failed_call": true + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000004", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "error" + }, + { + "error": { + "contract": 7 + } + } + ], + "data": { + "string": "escalating error to panic" + } + } + } + }, + "failed_call": true + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000004", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "error" + }, + { + "error": { + "contract": 7 + } + } + ], + "data": { + "string": "caught error from function" + } + } + } + }, + "failed_call": true + }, + { + "event": { + "ext": "v0", + "contract_id": null, + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "error" + }, + { + "error": { + "contract": 7 + } + } + ], + "data": { + "vec": [ + { + "string": "contract call failed" + }, + { + "symbol": "get_bids" + }, + { + "vec": [ + { + "u64": 404 + } + ] + } + ] + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": null, + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "error" + }, + { + "error": { + "contract": 7 + } + } + ], + "data": { + "string": "escalating error to panic" + } + } + } + }, + "failed_call": false + } + ] +} \ No newline at end of file diff --git a/contracts/job_registry/test_snapshots/test/test_get_deliverable_without_submission_panics.1.json b/contracts/job_registry/test_snapshots/test/test_get_deliverable_without_submission_panics.1.json index b1843590..cdef3115 100644 --- a/contracts/job_registry/test_snapshots/test/test_get_deliverable_without_submission_panics.1.json +++ b/contracts/job_registry/test_snapshots/test/test_get_deliverable_without_submission_panics.1.json @@ -142,7 +142,7 @@ "key": { "vec": [ { - "symbol": "Bids" + "symbol": "BidCount" }, { "u64": 1 @@ -162,7 +162,7 @@ "key": { "vec": [ { - "symbol": "Bids" + "symbol": "BidCount" }, { "u64": 1 @@ -171,7 +171,7 @@ }, "durability": "persistent", "val": { - "vec": [] + "u32": 0 } } }, diff --git a/contracts/job_registry/test_snapshots/test/test_late_bid_after_acceptance_panics_with_job_not_open.1.json b/contracts/job_registry/test_snapshots/test/test_late_bid_after_acceptance_panics_with_job_not_open.1.json new file mode 100644 index 00000000..5941fed7 --- /dev/null +++ b/contracts/job_registry/test_snapshots/test/test_late_bid_after_acceptance_panics_with_job_not_open.1.json @@ -0,0 +1,1244 @@ +{ + "generators": { + "address": 5, + "nonce": 0 + }, + "auth": [ + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "initialize", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "post_job", + "args": [ + { + "u64": 1 + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "bytes": "516d48617368" + }, + { + "i128": { + "hi": 0, + "lo": 5000 + } + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "submit_bid", + "args": [ + { + "u64": 1 + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + }, + { + "bytes": "516d50726f706f73616c" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "accept_bid", + "args": [ + { + "u64": 1 + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [] + ], + "ledger": { + "protocol_version": 21, + "sequence_number": 0, + "timestamp": 0, + "network_id": "0000000000000000000000000000000000000000000000000000000000000000", + "base_reserve": 0, + "min_persistent_entry_ttl": 4096, + "min_temp_entry_ttl": 16, + "max_entry_ttl": 6312000, + "ledger_entries": [ + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "ledger_key_nonce": { + "nonce": 801925984706572462 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "ledger_key_nonce": { + "nonce": 801925984706572462 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 4837995959683129791 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 4837995959683129791 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 5541220902715666415 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 5541220902715666415 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "ledger_key_nonce": { + "nonce": 1033654523790656264 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "ledger_key_nonce": { + "nonce": 1033654523790656264 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "key": { + "vec": [ + { + "symbol": "BidByIndex" + }, + { + "u64": 1 + }, + { + "u32": 0 + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "key": { + "vec": [ + { + "symbol": "BidByIndex" + }, + { + "u64": 1 + }, + { + "u32": 0 + } + ] + }, + "durability": "persistent", + "val": { + "map": [ + { + "key": { + "symbol": "freelancer" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + }, + { + "key": { + "symbol": "proposal_hash" + }, + "val": { + "bytes": "516d50726f706f73616c" + } + } + ] + } + } + }, + "ext": "v0" + }, + 4095 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "key": { + "vec": [ + { + "symbol": "BidCount" + }, + { + "u64": 1 + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "key": { + "vec": [ + { + "symbol": "BidCount" + }, + { + "u64": 1 + } + ] + }, + "durability": "persistent", + "val": { + "u32": 1 + } + } + }, + "ext": "v0" + }, + 4095 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "key": { + "vec": [ + { + "symbol": "BidLookup" + }, + { + "u64": 1 + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "key": { + "vec": [ + { + "symbol": "BidLookup" + }, + { + "u64": 1 + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + ] + }, + "durability": "persistent", + "val": { + "map": [ + { + "key": { + "symbol": "freelancer" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + }, + { + "key": { + "symbol": "proposal_hash" + }, + "val": { + "bytes": "516d50726f706f73616c" + } + } + ] + } + } + }, + "ext": "v0" + }, + 4095 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "key": { + "vec": [ + { + "symbol": "Job" + }, + { + "u64": 1 + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "key": { + "vec": [ + { + "symbol": "Job" + }, + { + "u64": 1 + } + ] + }, + "durability": "persistent", + "val": { + "map": [ + { + "key": { + "symbol": "budget_stroops" + }, + "val": { + "i128": { + "hi": 0, + "lo": 5000 + } + } + }, + { + "key": { + "symbol": "client" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + }, + { + "key": { + "symbol": "freelancer" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + }, + { + "key": { + "symbol": "metadata_hash" + }, + "val": { + "bytes": "516d48617368" + } + }, + { + "key": { + "symbol": "status" + }, + "val": { + "vec": [ + { + "symbol": "Assigned" + } + ] + } + } + ] + } + } + }, + "ext": "v0" + }, + 4095 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "key": "ledger_key_contract_instance", + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": [ + { + "key": { + "vec": [ + { + "symbol": "Admin" + } + ] + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + }, + { + "key": { + "vec": [ + { + "symbol": "NextJobId" + } + ] + }, + "val": { + "u64": 2 + } + } + ] + } + } + } + }, + "ext": "v0" + }, + 4095 + ] + ], + [ + { + "contract_code": { + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_code": { + "ext": "v0", + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "code": "" + } + }, + "ext": "v0" + }, + 4095 + ] + ] + ] + }, + "events": [ + { + "event": { + "ext": "v0", + "contract_id": null, + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_call" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000004" + }, + { + "symbol": "initialize" + } + ], + "data": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000004", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "log" + } + ], + "data": { + "vec": [ + { + "string": "JobRegistry initialized with admin: {}" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + ] + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000004", + "type_": "contract", + "body": { + "v0": { + "topics": [ + { + "symbol": "init" + } + ], + "data": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000004", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_return" + }, + { + "symbol": "initialize" + } + ], + "data": "void" + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": null, + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_call" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000004" + }, + { + "symbol": "post_job" + } + ], + "data": { + "vec": [ + { + "u64": 1 + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "bytes": "516d48617368" + }, + { + "i128": { + "hi": 0, + "lo": 5000 + } + } + ] + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000004", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "log" + } + ], + "data": { + "vec": [ + { + "string": "post_job: id {} client {} budget {}" + }, + { + "u64": 1 + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "i128": { + "hi": 0, + "lo": 5000 + } + } + ] + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000004", + "type_": "contract", + "body": { + "v0": { + "topics": [ + { + "symbol": "jobpost" + }, + { + "u64": 1 + } + ], + "data": { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "i128": { + "hi": 0, + "lo": 5000 + } + } + ] + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000004", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_return" + }, + { + "symbol": "post_job" + } + ], + "data": "void" + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": null, + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_call" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000004" + }, + { + "symbol": "submit_bid" + } + ], + "data": { + "vec": [ + { + "u64": 1 + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + }, + { + "bytes": "516d50726f706f73616c" + } + ] + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000004", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "log" + } + ], + "data": { + "vec": [ + { + "string": "submit_bid: id {} freelancer {}" + }, + { + "u64": 1 + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + ] + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000004", + "type_": "contract", + "body": { + "v0": { + "topics": [ + { + "symbol": "bid" + }, + { + "u64": 1 + } + ], + "data": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000004", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_return" + }, + { + "symbol": "submit_bid" + } + ], + "data": "void" + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": null, + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_call" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000004" + }, + { + "symbol": "accept_bid" + } + ], + "data": { + "vec": [ + { + "u64": 1 + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + ] + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000004", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "log" + } + ], + "data": { + "vec": [ + { + "string": "accept_bid: id {} client {} freelancer {}" + }, + { + "u64": 1 + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + ] + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000004", + "type_": "contract", + "body": { + "v0": { + "topics": [ + { + "symbol": "accept" + }, + { + "u64": 1 + } + ], + "data": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000004", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_return" + }, + { + "symbol": "accept_bid" + } + ], + "data": "void" + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": null, + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_call" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000004" + }, + { + "symbol": "submit_bid" + } + ], + "data": { + "vec": [ + { + "u64": 1 + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM" + }, + { + "bytes": "516d4c61746550726f706f73616c" + } + ] + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000004", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "error" + }, + { + "error": { + "contract": 8 + } + } + ], + "data": { + "vec": [ + { + "string": "failing with contract error" + }, + { + "u32": 8 + } + ] + } + } + } + }, + "failed_call": true + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000004", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "error" + }, + { + "error": { + "contract": 8 + } + } + ], + "data": { + "string": "escalating error to panic" + } + } + } + }, + "failed_call": true + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000004", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "error" + }, + { + "error": { + "contract": 8 + } + } + ], + "data": { + "string": "caught error from function" + } + } + } + }, + "failed_call": true + }, + { + "event": { + "ext": "v0", + "contract_id": null, + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "error" + }, + { + "error": { + "contract": 8 + } + } + ], + "data": { + "vec": [ + { + "string": "contract call failed" + }, + { + "symbol": "submit_bid" + }, + { + "vec": [ + { + "u64": 1 + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM" + }, + { + "bytes": "516d4c61746550726f706f73616c" + } + ] + } + ] + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": null, + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "error" + }, + { + "error": { + "contract": 8 + } + } + ], + "data": { + "string": "escalating error to panic" + } + } + } + }, + "failed_call": false + } + ] +} \ No newline at end of file diff --git a/contracts/job_registry/test_snapshots/test/test_mark_disputed_from_open_panics.1.json b/contracts/job_registry/test_snapshots/test/test_mark_disputed_from_open_panics.1.json index e4726b2f..26431f4d 100644 --- a/contracts/job_registry/test_snapshots/test/test_mark_disputed_from_open_panics.1.json +++ b/contracts/job_registry/test_snapshots/test/test_mark_disputed_from_open_panics.1.json @@ -145,7 +145,7 @@ "key": { "vec": [ { - "symbol": "Bids" + "symbol": "BidCount" }, { "u64": 1 @@ -165,7 +165,7 @@ "key": { "vec": [ { - "symbol": "Bids" + "symbol": "BidCount" }, { "u64": 1 @@ -174,7 +174,7 @@ }, "durability": "persistent", "val": { - "vec": [] + "u32": 0 } } }, diff --git a/contracts/job_registry/test_snapshots/test/test_oversized_cid_panics_with_invalid_hash.1.json b/contracts/job_registry/test_snapshots/test/test_oversized_cid_panics_with_invalid_hash.1.json new file mode 100644 index 00000000..f5252812 --- /dev/null +++ b/contracts/job_registry/test_snapshots/test/test_oversized_cid_panics_with_invalid_hash.1.json @@ -0,0 +1,447 @@ +{ + "generators": { + "address": 4, + "nonce": 0 + }, + "auth": [ + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "initialize", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [] + ], + "ledger": { + "protocol_version": 21, + "sequence_number": 0, + "timestamp": 0, + "network_id": "0000000000000000000000000000000000000000000000000000000000000000", + "base_reserve": 0, + "min_persistent_entry_ttl": 4096, + "min_temp_entry_ttl": 16, + "max_entry_ttl": 6312000, + "ledger_entries": [ + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "ledger_key_nonce": { + "nonce": 801925984706572462 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "ledger_key_nonce": { + "nonce": 801925984706572462 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "key": "ledger_key_contract_instance", + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": [ + { + "key": { + "vec": [ + { + "symbol": "Admin" + } + ] + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + }, + { + "key": { + "vec": [ + { + "symbol": "NextJobId" + } + ] + }, + "val": { + "u64": 1 + } + } + ] + } + } + } + }, + "ext": "v0" + }, + 4095 + ] + ], + [ + { + "contract_code": { + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_code": { + "ext": "v0", + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "code": "" + } + }, + "ext": "v0" + }, + 4095 + ] + ] + ] + }, + "events": [ + { + "event": { + "ext": "v0", + "contract_id": null, + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_call" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000004" + }, + { + "symbol": "initialize" + } + ], + "data": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000004", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "log" + } + ], + "data": { + "vec": [ + { + "string": "JobRegistry initialized with admin: {}" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + ] + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000004", + "type_": "contract", + "body": { + "v0": { + "topics": [ + { + "symbol": "init" + } + ], + "data": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000004", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_return" + }, + { + "symbol": "initialize" + } + ], + "data": "void" + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": null, + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_call" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000004" + }, + { + "symbol": "post_job" + } + ], + "data": { + "vec": [ + { + "u64": 1 + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "bytes": "61616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161" + }, + { + "i128": { + "hi": 0, + "lo": 5000 + } + } + ] + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000004", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "error" + }, + { + "error": { + "contract": 5 + } + } + ], + "data": { + "vec": [ + { + "string": "failing with contract error" + }, + { + "u32": 5 + } + ] + } + } + } + }, + "failed_call": true + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000004", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "error" + }, + { + "error": { + "contract": 5 + } + } + ], + "data": { + "string": "escalating error to panic" + } + } + } + }, + "failed_call": true + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000004", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "error" + }, + { + "error": { + "contract": 5 + } + } + ], + "data": { + "string": "caught error from function" + } + } + } + }, + "failed_call": true + }, + { + "event": { + "ext": "v0", + "contract_id": null, + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "error" + }, + { + "error": { + "contract": 5 + } + } + ], + "data": { + "vec": [ + { + "string": "contract call failed" + }, + { + "symbol": "post_job" + }, + { + "vec": [ + { + "u64": 1 + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "bytes": "61616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161" + }, + { + "i128": { + "hi": 0, + "lo": 5000 + } + } + ] + } + ] + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": null, + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "error" + }, + { + "error": { + "contract": 5 + } + } + ], + "data": { + "string": "escalating error to panic" + } + } + } + }, + "failed_call": false + } + ] +} \ No newline at end of file diff --git a/contracts/job_registry/test_snapshots/test/test_post_job_auto_allocates_sequential_ids.1.json b/contracts/job_registry/test_snapshots/test/test_post_job_auto_allocates_sequential_ids.1.json index 7c1e05de..4d4caf7a 100644 --- a/contracts/job_registry/test_snapshots/test/test_post_job_auto_allocates_sequential_ids.1.json +++ b/contracts/job_registry/test_snapshots/test/test_post_job_auto_allocates_sequential_ids.1.json @@ -209,7 +209,7 @@ "key": { "vec": [ { - "symbol": "Bids" + "symbol": "BidCount" }, { "u64": 1 @@ -229,7 +229,7 @@ "key": { "vec": [ { - "symbol": "Bids" + "symbol": "BidCount" }, { "u64": 1 @@ -238,7 +238,7 @@ }, "durability": "persistent", "val": { - "vec": [] + "u32": 0 } } }, @@ -254,7 +254,7 @@ "key": { "vec": [ { - "symbol": "Bids" + "symbol": "BidCount" }, { "u64": 2 @@ -274,7 +274,7 @@ "key": { "vec": [ { - "symbol": "Bids" + "symbol": "BidCount" }, { "u64": 2 @@ -283,7 +283,7 @@ }, "durability": "persistent", "val": { - "vec": [] + "u32": 0 } } }, diff --git a/contracts/job_registry/test_snapshots/test/test_post_job_with_explicit_id_updates_next_job_id.1.json b/contracts/job_registry/test_snapshots/test/test_post_job_with_explicit_id_updates_next_job_id.1.json index 46ba7e16..00523819 100644 --- a/contracts/job_registry/test_snapshots/test/test_post_job_with_explicit_id_updates_next_job_id.1.json +++ b/contracts/job_registry/test_snapshots/test/test_post_job_with_explicit_id_updates_next_job_id.1.json @@ -145,7 +145,7 @@ "key": { "vec": [ { - "symbol": "Bids" + "symbol": "BidCount" }, { "u64": 42 @@ -165,7 +165,7 @@ "key": { "vec": [ { - "symbol": "Bids" + "symbol": "BidCount" }, { "u64": 42 @@ -174,7 +174,7 @@ }, "durability": "persistent", "val": { - "vec": [] + "u32": 0 } } }, diff --git a/contracts/job_registry/test_snapshots/test/test_set_escrow_deployer_round_trip.1.json b/contracts/job_registry/test_snapshots/test/test_set_escrow_deployer_round_trip.1.json new file mode 100644 index 00000000..b49d897d --- /dev/null +++ b/contracts/job_registry/test_snapshots/test/test_set_escrow_deployer_round_trip.1.json @@ -0,0 +1,452 @@ +{ + "generators": { + "address": 4, + "nonce": 0 + }, + "auth": [ + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "initialize", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "set_escrow_deployer", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [] + ], + "ledger": { + "protocol_version": 21, + "sequence_number": 0, + "timestamp": 0, + "network_id": "0000000000000000000000000000000000000000000000000000000000000000", + "base_reserve": 0, + "min_persistent_entry_ttl": 4096, + "min_temp_entry_ttl": 16, + "max_entry_ttl": 6312000, + "ledger_entries": [ + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "ledger_key_nonce": { + "nonce": 801925984706572462 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "ledger_key_nonce": { + "nonce": 801925984706572462 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "ledger_key_nonce": { + "nonce": 5541220902715666415 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "ledger_key_nonce": { + "nonce": 5541220902715666415 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "key": "ledger_key_contract_instance", + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": [ + { + "key": { + "vec": [ + { + "symbol": "Admin" + } + ] + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + }, + { + "key": { + "vec": [ + { + "symbol": "EscrowDeployer" + } + ] + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + }, + { + "key": { + "vec": [ + { + "symbol": "NextJobId" + } + ] + }, + "val": { + "u64": 1 + } + } + ] + } + } + } + }, + "ext": "v0" + }, + 4095 + ] + ], + [ + { + "contract_code": { + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_code": { + "ext": "v0", + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "code": "" + } + }, + "ext": "v0" + }, + 4095 + ] + ] + ] + }, + "events": [ + { + "event": { + "ext": "v0", + "contract_id": null, + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_call" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000004" + }, + { + "symbol": "initialize" + } + ], + "data": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000004", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "log" + } + ], + "data": { + "vec": [ + { + "string": "JobRegistry initialized with admin: {}" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + ] + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000004", + "type_": "contract", + "body": { + "v0": { + "topics": [ + { + "symbol": "init" + } + ], + "data": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000004", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_return" + }, + { + "symbol": "initialize" + } + ], + "data": "void" + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": null, + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_call" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000004" + }, + { + "symbol": "set_escrow_deployer" + } + ], + "data": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000004", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "log" + } + ], + "data": { + "vec": [ + { + "string": "escrow_deployer configured: {}" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + ] + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000004", + "type_": "contract", + "body": { + "v0": { + "topics": [ + { + "symbol": "escrow" + } + ], + "data": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000004", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_return" + }, + { + "symbol": "set_escrow_deployer" + } + ], + "data": "void" + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": null, + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_call" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000004" + }, + { + "symbol": "get_escrow_deployer" + } + ], + "data": "void" + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000004", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_return" + }, + { + "symbol": "get_escrow_deployer" + } + ], + "data": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + } + } + }, + "failed_call": false + } + ] +} \ No newline at end of file diff --git a/contracts/job_registry/test_snapshots/test/test_unauthorized_accept_bid_panics_with_specific_error.1.json b/contracts/job_registry/test_snapshots/test/test_unauthorized_accept_bid_panics_with_specific_error.1.json new file mode 100644 index 00000000..f4767467 --- /dev/null +++ b/contracts/job_registry/test_snapshots/test/test_unauthorized_accept_bid_panics_with_specific_error.1.json @@ -0,0 +1,1071 @@ +{ + "generators": { + "address": 5, + "nonce": 0 + }, + "auth": [ + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "initialize", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "post_job", + "args": [ + { + "u64": 1 + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "bytes": "516d48617368" + }, + { + "i128": { + "hi": 0, + "lo": 5000 + } + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "submit_bid", + "args": [ + { + "u64": 1 + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + }, + { + "bytes": "516d50726f706f73616c" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [] + ], + "ledger": { + "protocol_version": 21, + "sequence_number": 0, + "timestamp": 0, + "network_id": "0000000000000000000000000000000000000000000000000000000000000000", + "base_reserve": 0, + "min_persistent_entry_ttl": 4096, + "min_temp_entry_ttl": 16, + "max_entry_ttl": 6312000, + "ledger_entries": [ + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "ledger_key_nonce": { + "nonce": 801925984706572462 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "ledger_key_nonce": { + "nonce": 801925984706572462 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 5541220902715666415 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 5541220902715666415 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "ledger_key_nonce": { + "nonce": 1033654523790656264 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "ledger_key_nonce": { + "nonce": 1033654523790656264 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "key": { + "vec": [ + { + "symbol": "BidByIndex" + }, + { + "u64": 1 + }, + { + "u32": 0 + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "key": { + "vec": [ + { + "symbol": "BidByIndex" + }, + { + "u64": 1 + }, + { + "u32": 0 + } + ] + }, + "durability": "persistent", + "val": { + "map": [ + { + "key": { + "symbol": "freelancer" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + }, + { + "key": { + "symbol": "proposal_hash" + }, + "val": { + "bytes": "516d50726f706f73616c" + } + } + ] + } + } + }, + "ext": "v0" + }, + 4095 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "key": { + "vec": [ + { + "symbol": "BidCount" + }, + { + "u64": 1 + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "key": { + "vec": [ + { + "symbol": "BidCount" + }, + { + "u64": 1 + } + ] + }, + "durability": "persistent", + "val": { + "u32": 1 + } + } + }, + "ext": "v0" + }, + 4095 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "key": { + "vec": [ + { + "symbol": "BidLookup" + }, + { + "u64": 1 + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "key": { + "vec": [ + { + "symbol": "BidLookup" + }, + { + "u64": 1 + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + ] + }, + "durability": "persistent", + "val": { + "map": [ + { + "key": { + "symbol": "freelancer" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + }, + { + "key": { + "symbol": "proposal_hash" + }, + "val": { + "bytes": "516d50726f706f73616c" + } + } + ] + } + } + }, + "ext": "v0" + }, + 4095 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "key": { + "vec": [ + { + "symbol": "Job" + }, + { + "u64": 1 + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "key": { + "vec": [ + { + "symbol": "Job" + }, + { + "u64": 1 + } + ] + }, + "durability": "persistent", + "val": { + "map": [ + { + "key": { + "symbol": "budget_stroops" + }, + "val": { + "i128": { + "hi": 0, + "lo": 5000 + } + } + }, + { + "key": { + "symbol": "client" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + }, + { + "key": { + "symbol": "freelancer" + }, + "val": "void" + }, + { + "key": { + "symbol": "metadata_hash" + }, + "val": { + "bytes": "516d48617368" + } + }, + { + "key": { + "symbol": "status" + }, + "val": { + "vec": [ + { + "symbol": "Open" + } + ] + } + } + ] + } + } + }, + "ext": "v0" + }, + 4095 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "key": "ledger_key_contract_instance", + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": [ + { + "key": { + "vec": [ + { + "symbol": "Admin" + } + ] + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + }, + { + "key": { + "vec": [ + { + "symbol": "NextJobId" + } + ] + }, + "val": { + "u64": 2 + } + } + ] + } + } + } + }, + "ext": "v0" + }, + 4095 + ] + ], + [ + { + "contract_code": { + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_code": { + "ext": "v0", + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "code": "" + } + }, + "ext": "v0" + }, + 4095 + ] + ] + ] + }, + "events": [ + { + "event": { + "ext": "v0", + "contract_id": null, + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_call" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000004" + }, + { + "symbol": "initialize" + } + ], + "data": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000004", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "log" + } + ], + "data": { + "vec": [ + { + "string": "JobRegistry initialized with admin: {}" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + ] + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000004", + "type_": "contract", + "body": { + "v0": { + "topics": [ + { + "symbol": "init" + } + ], + "data": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000004", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_return" + }, + { + "symbol": "initialize" + } + ], + "data": "void" + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": null, + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_call" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000004" + }, + { + "symbol": "post_job" + } + ], + "data": { + "vec": [ + { + "u64": 1 + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "bytes": "516d48617368" + }, + { + "i128": { + "hi": 0, + "lo": 5000 + } + } + ] + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000004", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "log" + } + ], + "data": { + "vec": [ + { + "string": "post_job: id {} client {} budget {}" + }, + { + "u64": 1 + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "i128": { + "hi": 0, + "lo": 5000 + } + } + ] + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000004", + "type_": "contract", + "body": { + "v0": { + "topics": [ + { + "symbol": "jobpost" + }, + { + "u64": 1 + } + ], + "data": { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "i128": { + "hi": 0, + "lo": 5000 + } + } + ] + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000004", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_return" + }, + { + "symbol": "post_job" + } + ], + "data": "void" + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": null, + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_call" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000004" + }, + { + "symbol": "submit_bid" + } + ], + "data": { + "vec": [ + { + "u64": 1 + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + }, + { + "bytes": "516d50726f706f73616c" + } + ] + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000004", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "log" + } + ], + "data": { + "vec": [ + { + "string": "submit_bid: id {} freelancer {}" + }, + { + "u64": 1 + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + ] + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000004", + "type_": "contract", + "body": { + "v0": { + "topics": [ + { + "symbol": "bid" + }, + { + "u64": 1 + } + ], + "data": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000004", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_return" + }, + { + "symbol": "submit_bid" + } + ], + "data": "void" + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": null, + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "fn_call" + }, + { + "bytes": "0000000000000000000000000000000000000000000000000000000000000004" + }, + { + "symbol": "accept_bid" + } + ], + "data": { + "vec": [ + { + "u64": 1 + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + ] + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000004", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "error" + }, + { + "error": { + "contract": 9 + } + } + ], + "data": { + "vec": [ + { + "string": "failing with contract error" + }, + { + "u32": 9 + } + ] + } + } + } + }, + "failed_call": true + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000004", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "error" + }, + { + "error": { + "contract": 9 + } + } + ], + "data": { + "string": "escalating error to panic" + } + } + } + }, + "failed_call": true + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000004", + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "error" + }, + { + "error": { + "contract": 9 + } + } + ], + "data": { + "string": "caught error from function" + } + } + } + }, + "failed_call": true + }, + { + "event": { + "ext": "v0", + "contract_id": null, + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "error" + }, + { + "error": { + "contract": 9 + } + } + ], + "data": { + "vec": [ + { + "string": "contract call failed" + }, + { + "symbol": "accept_bid" + }, + { + "vec": [ + { + "u64": 1 + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + ] + } + ] + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": null, + "type_": "diagnostic", + "body": { + "v0": { + "topics": [ + { + "symbol": "error" + }, + { + "error": { + "contract": 9 + } + } + ], + "data": { + "string": "escalating error to panic" + } + } + } + }, + "failed_call": false + } + ] +} \ No newline at end of file