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