From afe60aee6279b6e0f1a0137766b89ae40997c2cc Mon Sep 17 00:00:00 2001 From: Emma Zhong Date: Mon, 19 Sep 2022 18:28:54 -0700 Subject: [PATCH] [governance] add delegation staking pool implementation (#4187) * [governance] add draft delegation staking pool implementation * distribute pool tokens at epoch boundaries * refactor staking pool code and add delegation switching * update rust version of sui system state * [staking] use vector for pending delegations --- ...tests__empty_genesis_snapshot_matches.snap | 2 +- ..._populated_genesis_snapshot_matches-5.snap | 18 +- ...rical_transaction_cost__good_snapshot.snap | 6 +- .../sources/epoch_time_lock.move | 2 +- .../sources/governance/delegation.move | 207 ----------- .../governance/epoch_reward_record.move | 59 --- .../sources/governance/staking_pool.move | 343 ++++++++++++++++++ .../sources/governance/sui_system.move | 90 ++--- .../sources/governance/validator.move | 102 +++--- .../sources/governance/validator_set.move | 165 +++++---- crates/sui-framework/sources/locked_coin.move | 1 - crates/sui-framework/sources/vec_map.move | 10 + .../sui-framework/tests/delegation_tests.move | 178 +-------- .../tests/validator_set_tests.move | 16 +- .../sui-framework/tests/validator_tests.move | 4 +- crates/sui-types/src/sui_system_state.rs | 29 +- 16 files changed, 589 insertions(+), 643 deletions(-) delete mode 100644 crates/sui-framework/sources/governance/delegation.move delete mode 100644 crates/sui-framework/sources/governance/epoch_reward_record.move create mode 100644 crates/sui-framework/sources/governance/staking_pool.move diff --git a/crates/sui-config/tests/snapshots/snapshot_tests__empty_genesis_snapshot_matches.snap b/crates/sui-config/tests/snapshots/snapshot_tests__empty_genesis_snapshot_matches.snap index 2d3884ff80dbc..a40344bf49b1b 100644 --- a/crates/sui-config/tests/snapshots/snapshot_tests__empty_genesis_snapshot_matches.snap +++ b/crates/sui-config/tests/snapshots/snapshot_tests__empty_genesis_snapshot_matches.snap @@ -2,5 +2,5 @@ source: crates/sui-config/tests/snapshot_tests.rs expression: genesis --- -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ExMWDBcQAQcIAAABBggAAQMBCAACBggABggAAQEBBggBCgUKAgoCCgIKAgoCCwIBCAMLBAEIBQMHCAYCBwgAAwQHCAALAgEIAwsEAQgFBwgGBQcIAAcIBwMDBwgGAQUDCgIFCgICAQEDAQEDAQIBCgIBCAgBCAMBBgsCAQkABAsCAQgDBQsEAQgFBwgGAwcIBwMHCAYCCgIKAgEGCQACBwoJAAoJAAQKAgoCCgIKAgdnZW5lc2lzCnN1aV9zeXN0ZW0NdmFsaWRhdG9yX3NldAl2YWxpZGF0b3IFYXNjaWkDYmNzBm9wdGlvbgZ2ZWN0b3IHYmFsYW5jZQZjcnlwdG8PZXBvY2hfdGltZV9sb2NrBXN0YWtlA3N1aQp0eF9jb250ZXh0CVZhbGlkYXRvchFWYWxpZGF0b3JNZXRhZGF0YRphZGp1c3Rfc3Rha2VfYW5kX2dhc19wcmljZQ9kZWxlZ2F0ZV9hbW91bnQPZGVsZWdhdG9yX2NvdW50B2Rlc3Ryb3kJZ2FzX3ByaWNlDGlzX2R1cGxpY2F0ZQhtZXRhZGF0YQdCYWxhbmNlA1NVSQZPcHRpb24NRXBvY2hUaW1lTG9jawlUeENvbnRleHQDbmV3FHBlbmRpbmdfc3Rha2VfYW1vdW50EHBlbmRpbmdfd2l0aGRyYXcWcmVxdWVzdF9hZGRfZGVsZWdhdGlvbhFyZXF1ZXN0X2FkZF9zdGFrZRlyZXF1ZXN0X3JlbW92ZV9kZWxlZ2F0aW9uFXJlcXVlc3Rfc2V0X2dhc19wcmljZQVTdGFrZRZyZXF1ZXN0X3dpdGhkcmF3X3N0YWtlDHN0YWtlX2Ftb3VudAtzdWlfYWRkcmVzcxp2ZXJpZnlfcHJvb2Zfb2ZfcG9zc2Vzc2lvbgpkZWxlZ2F0aW9uDXBlbmRpbmdfc3Rha2UScGVuZGluZ19kZWxlZ2F0aW9uG3BlbmRpbmdfZGVsZWdhdGlvbl93aXRoZHJhdxdwZW5kaW5nX2RlbGVnYXRvcl9jb3VudCBwZW5kaW5nX2RlbGVnYXRvcl93aXRoZHJhd19jb3VudAxwdWJrZXlfYnl0ZXMUbmV0d29ya19wdWJrZXlfYnl0ZXMTcHJvb2Zfb2ZfcG9zc2Vzc2lvbgRuYW1lC25ldF9hZGRyZXNzEG5leHRfZXBvY2hfc3Rha2UVbmV4dF9l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AQkACAgGCwcBCAgLAQEIAgMDCAALBwEICAEHCwcBCQABBgsBAQkAAwgIBQsBAQgCBAsBAQkACAgFBwgDCnN1aV9zeXN0ZW0KZGVsZWdhdGlvbgZvcHRpb24HYmFsYW5jZQRjb2luD2Vwb2NoX3RpbWVfbG9jawtsb2NrZWRfY29pbgZvYmplY3QDc3VpCHRyYW5zZmVyCnR4X2NvbnRleHQKRGVsZWdhdGlvbgRidXJuEGNhbl9jbGFpbV9yZXdhcmQHQmFsYW5jZQNTVUkJVHhDb250ZXh0DGNsYWltX3Jld2FyZARDb2luBmNyZWF0ZQpMb2NrZWRDb2luF2NyZWF0ZV9mcm9tX2xvY2tlZF9jb2luD2RlbGVnYXRlX2Ftb3VudAlpc19hY3RpdmURc3dpdGNoX2RlbGVnYXRpb24KdW5kZWxlZ2F0ZQl2YWxpZGF0b3ICaWQDVUlEEWFjdGl2ZV9kZWxlZ2F0aW9uBk9wdGlvbgxlbmRpbmdfZXBvY2gbbmV4dF9yZXdhcmRfdW5jbGFpbWVkX2Vwb2NoF2NvaW5fbG9ja2VkX3VudGlsX2Vwb2NoDUVwb2NoVGltZUxvY2sRdmFsaWRhdG9yX2FkZHJlc3MGZGVsZXRlDGRlc3Ryb3lfbm9uZQZib3Jyb3cGc2VuZGVyDGZyb21fYmFsYW5jZQV2YWx1ZQNuZXcMaW50b19iYWxhbmNlBHNvbWUEbm9uZQdpc19zb21lB2lzX25vbmUFZXBvY2gHZXh0cmFjdBBuZXdfZnJvbV9iYWxhbmNlAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAQACBxsIBh0LBwELAQEIAh8LBwEDFgMgAyELBwEICCMFAAEEAAwgDgARBiADBgYAAAAAAAAAACcLABMAAQwCDAYBDAMMAQwFCwURCgsBOAALAjgBDgM4AhQMBAsGCwQhAx8GAAAAAAAAAAAnAgEBAAATKQsCCgAQABQiAwcFCggMAwUQCgAQARQKASQMAwsDAxMFFwsAAQkCCgARBiADHAUlCwAQAjgCFAwECwQLASQCCwABCAICAwAACxIKAi4RDQwDCwELAjgDCwM4BAoAEAEUBgEAAAAAAAAAFgsADwEVAgMDAAAaFQ4COAUMBAoDERELAjgGOAc4CAsECwA4CQsBEgAMBQsF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AAEGCA0BBgsIAQkAAgcLCAEJAAMCBwsIAQkACwgBCQAFBggNAwMDBwgCAwcIDQcLCAEIBwcIAgcHCAMDBQMLCAEIBwMFAQYIBAMGCAMDBQEBAQYIAwIHCAQDAwcIAwsIAQgHBwgCAwMIAAgNAQoIBQEIDQEIDAEIAAEJAAIDAwEGCwkBCQADBwgNBQMEAwULCQEIBwcIAgEGCwoBCQAEAwULCgEIBwcIAgELCQEJAAEIDgELDwEJAAQHCA0LCAEIBwsPAQgOBwgCAgsIAQgHCA4BCwoBCQACCwgBCQAIDgIDCAUKBQoCCgIKAgoCCgILCAEIBwsPAQgOAwcIAgEIBQIHCA0IBQMHCAMDBwgCAgcIDQcIAgIHCA0GCAIDBwgNAwcIAgIDBQMHCAMFBwgCBQcIDQcICwMDBwgCAgYIDQUHZ2VuZXNpcwpzdWlfc3lzdGVtBm9wdGlvbgdiYWxhbmNlBGNvaW4KZGVsZWdhdGlvbhNlcG9jaF9yZXdhcmRfcmVjb3JkD2Vwb2NoX3RpbWVfbG9jawtsb2NrZWRfY29pbgZvYmplY3QFc3Rha2UDc3VpCHRyYW5zZmVyCnR4X2NvbnRleHQJdmFsaWRhdG9yDXZhbGlkYXRvcl9zZXQOU3VpU3lzdGVtU3RhdGUQU3lzdGVtUGFyYW1ldGVycwlUeENvbnRleHQNYWR2YW5jZV9lcG9jaApEZWxlZ2F0aW9uEUVwb2NoUmV3YXJkUmVjb3JkF2NsYWltX2RlbGVnYXRpb25fcmV3YXJkCVZhbGlkYXRvcgZTdXBwbHkDU1VJB0JhbGFuY2UGY3JlYXRlBWVwb2NoBENvaW4WcmVxdWVzdF9hZGRfZGVsZWdhdGlvbgpMb2NrZWRDb2luJ3JlcXVlc3RfYWRkX2RlbGVnYXRpb25fd2l0aF9sb2NrZWRfY29pbhFyZXF1ZXN0X2FkZF9zdGFrZSJyZXF1ZXN0X2FkZF9zdGFrZV93aXRoX2xvY2tlZF9jb2luFXJlcXVlc3RfYWRkX3ZhbGlkYXRvchlyZXF1ZXN0X3JlbW92ZV9kZWxlZ2F0aW9uGHJlcXVlc3RfcmVtb3ZlX3ZhbGlkYXRvchVyZXF1ZXN0X3NldF9nYXNfcHJpY2UZcmVxdWVzdF9zd2l0Y2hfZGVsZWdhdGlvbgVTdGFrZRZyZXF1ZXN0X3dpdGhkcmF3X3N0YWtlGXZhbGlkYXRvcl9kZWxlZ2F0ZV9hbW91bnQZdmFsaWRhdG9yX2RlbGVnYXRvcl9jb3VudAJpZANVSUQKdmFsaWRhdG9ycwxWYWxpZGF0b3JTZXQKc3VpX3N1cHBseQxzdG9yYWdlX2Z1bmQKcGFyYW1ldGVycxFkZWxlZ2F0aW9uX3Jld2FyZBNyZWZlcmVuY2VfZ2FzX3ByaWNlE21pbl92YWxpZGF0b3Jfc3Rha2UdbWF4X3ZhbGlkYXRvcl9jYW5kaWRhdGVfY291bnQRc3RvcmFnZV9nYXNfcHJpY2UGc2VuZGVyD2luY3JlYXNlX3N1cHBseRZ0b3RhbF9kZWxlZ2F0aW9uX3N0YWtlFXRvdGFsX3ZhbGlkYXRvcl9zdGFrZQV2YWx1ZQVzcGxpdARqb2luFGNyZWF0ZV9lcG9jaF9yZWNvcmRzGmRlcml2ZV9yZWZlcmVuY2VfZ2FzX3ByaWNlEGNhbl9jbGFpbV9yZXdhcmQPZGVsZWdhdGVfYW1vdW50DGNsYWltX3Jld2FyZANuZXcQc3VpX3N5c3RlbV9zdGF0ZQR6ZXJvDHNoYXJlX29iamVjdBdjcmVhdGVfZnJvbV9sb2NrZWRfY29pbgxpbnRvX2JhbGFuY2UNRXBvY2hUaW1lTG9jawZPcHRpb24Ebm9uZQRzb21lGm5leHRfZXBvY2hfdmFsaWRhdG9yX2NvdW50CnVuZGVsZWdhdGURc3dpdGNoX2RlbGVnYXRpb24AAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAABBRQAAAAAAAAAAAAAAAAAAAAAAAAAAAACCCwIDBwDLggNMAsGAQgHMQsIAQgHMggBMwsIAQgHNAMBAgM1AzYDNwMAAQQAEWoKBC4REAcAIQMMCwABCwQBBgAAAAAAAAAAJwoADwALAjgADAoKAA8ACgM4AAwFCgAQARESDAYKABABERMMDAoAEAI4AQwJCgYLDBYLCRYMCwsGCgMYCgsaDAgNBQsIOAIMBwoADwILCjgDAQoADwMLBzgDAQoAEAEKABAEFAsDCwsKBBEXCgAQBBQGAQAAAAAAAAAWCgAPBBULAQoAEAQUIQNZCwABCwQBBgAAAAAAAAAAJwoADwENBQsEERgKABABERkKAA8FFQsADwILBTgDAQIB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AQsCAQgDCwYBCAcHCAQBCQAEBwoIAQUDCwYBAwEGCwYBCQABBwsGAQkAAgMLBgEDBAMDAwgAAgMIAQEGCgkAAgcKCQADAgcIAQMCBwgBBQEGCAQDBwgBAwsGAQMDBQMLBgEDAgYKCQAGCQAFBwgBBwgIAwMHCAQIBwoDAwcKAwMDAwMDCnN1aV9zeXN0ZW0NdmFsaWRhdG9yX3NldAZvcHRpb24GdmVjdG9yB2JhbGFuY2UTZXBvY2hfcmV3YXJkX3JlY29yZA9lcG9jaF90aW1lX2xvY2sOcHJpb3JpdHlfcXVldWUFc3Rha2UDc3VpCnR4X2NvbnRleHQJdmFsaWRhdG9yDFZhbGlkYXRvclNldAlWYWxpZGF0b3IaYWRqdXN0X3N0YWtlX2FuZF9nYXNfcHJpY2UHQmFsYW5jZQNTVUkJVHhDb250ZXh0DWFkdmFuY2VfZXBvY2gaY2FsY3VsYXRlX3F1b3J1bV90aHJlc2hvbGQqY2FsY3VsYXRlX3RvdGFsX3N0YWtlX2FuZF9xdW9ydW1fdGhyZXNob2xkG2NvbXB1dGVfcmV3YXJkX2Rpc3RyaWJ1dGlvbhxjb250YWluc19kdXBsaWNhdGVfdmFsaWRhdG9yFGNyZWF0ZV9lcG9jaF9yZWNvcmRzEVZhbGlkYXRvck1ldGFkYXRhHGRlcml2ZV9uZXh0X2Vwb2NoX3ZhbGlkYXRvcnMaZGVyaXZlX3JlZmVyZW5jZV9nYXNfcHJpY2URZGlzdHJpYnV0ZV9yZXdhcmQGT3B0aW9uDmZpbmRfdmFsaWRhdG9yEWdldF92YWxpZGF0b3JfbXV0EWdldF92YWxpZGF0b3JfcmVmE2lzX2FjdGl2ZV92YWxpZGF0b3IDbmV3Gm5leHRfZXBvY2hfdmFsaWRhdG9yX2NvdW50GHByb2Nlc3NfcGVuZGluZ19yZW1vdmFscxpwcm9jZXNzX3BlbmRpbmdfdmFsaWRhdG9ycxZyZXF1ZXN0X2FkZF9kZWxlZ2F0aW9uDUVwb2NoVGltZUxvY2sRcmVxdWVzdF9hZGRfc3Rha2UVcmVxdWVzdF9hZGRfdmFsaWRhdG9yGXJlcXVlc3RfcmVtb3ZlX2RlbGVnYXRpb24YcmVxdWVzdF9yZW1vdmVfdmFsaWRhdG9yFXJlcXVlc3Rfc2V0X2dhc19wcmljZQVT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1ZXN0X2FkZF9zdGFrZRVyZXF1ZXN0X3NldF9nYXNfcHJpY2UKRGVsZWdhdGlvbglTdGFrZWRTdWkbcmVxdWVzdF93aXRoZHJhd19kZWxlZ2F0aW9uBVN0YWtlFnJlcXVlc3Rfd2l0aGRyYXdfc3Rha2UMc3Rha2VfYW1vdW50C3N1aV9hZGRyZXNzGnZlcmlmeV9wcm9vZl9vZl9wb3NzZXNzaW9uDXBlbmRpbmdfc3Rha2UXZGVsZWdhdGlvbl9zdGFraW5nX3Bvb2wMcHVia2V5X2J5dGVzFG5ldHdvcmtfcHVia2V5X2J5dGVzE3Byb29mX29mX3Bvc3Nlc3Npb24EbmFtZQtuZXRfYWRkcmVzcxBuZXh0X2Vwb2NoX3N0YWtlFW5leHRfZXBvY2hfZGVsZWdhdGlvbhRuZXh0X2Vwb2NoX2dhc19wcmljZQtzdWlfYmFsYW5jZRdkZWFjdGl2YXRlX3N0YWtpbmdfcG9vbAV2YWx1ZQ1hZHZhbmNlX2Vwb2NoBlN0cmluZwZzdHJpbmcGY3JlYXRlBWVwb2NoDndpdGhkcmF3X3N0YWtlCHRvX2J5dGVzBmFwcGVuZBtibHMxMjM4MV92ZXJpZnlfd2l0aF9kb21haW4AAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAABCgIFBGtvc2sAAgYeCAEsAy8DIwMZAzAIBQECCS0FMQoCMgoCMwoCNAoCNQoCNgM3AzgDAAMAAAEpCgAQABQKABABFBYKABACFBcKAA8AFQYAAAAAAAAAAAoADwEVBgAAAAAAAAAACgAPAhUKABADEAQUCgAPBRUKABAAFAsAEAMQBhQhAygGAAAAAAAAAAAnAgEDAAABCwoAEAMQBxQLARcLAA8DDwcVAgIBAAABBAsAEAgRFQIDAwAAEwwLABMADAIBAQEBAQsCCwERFgIEAwAAARwKABADEAcUDgE4ABYKAA8DDwcVCgAPCAsBCwIRGAoALhECCwAQAxAHFCEDGwYAAAAAAAAAACcCBQEAAAEECwAQBRQCBgMAAAEDCwAPCAIHAwAAAQsKABADEAcUCwEWCwAPAw8HFQIIAQAAGC4KABADEAkUCgEQAxAJFCEDCwUOCAwCBRgKABADEAoUCgEQAxAKFCEMAgsCAxsFIgsAAQsBAQgMAwUsCwAQAxA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CAgcIAAcIAgMHCAADBwgCBQcIAAgJBwgKBQcIAgUHCAAHCAkHCAoDBwgCBAcIAAcICwMHCAICBggABQgLBgEIBQMLBgEIBQMDCwYBCAUDAwEGCAIBBQEIBQIHCwQBCQADAQsGAQkAAQYIDQEGCwYBCQACBwsGAQkAAwIHCwYBCQALBgEJAAQHCA0HCwYBCAUHCwYBCAUHCAIDAwgACA0BCggDAQgNAQgMAQgAAQkAAQsHAQkAAQgOAQsPAQkABQcIDQULBgEIBQsPAQgOBwgCAgsGAQgFCA4BCwgBCQACCwYBCQAIDgQHCA0LBgEIBQsPAQgOBwgCAgMIAwEGCwcBCQAKBQoCCgIKAgoCCgILBgEIBQsPAQgOAwcIAgEIAwIHCA0IAwIHCA0HCAICBwgNBggCAwcIDQMHCAIFBwgNCAkHCAoFBwgCBQcIDQcICQcICgMHCAIFBwgNBwgLAwMHCAICBggNBQdnZW5lc2lzCnN1aV9zeXN0ZW0Gb3B0aW9uB2JhbGFuY2UEY29pbg9lcG9jaF90aW1lX2xvY2sLbG9ja2VkX2NvaW4Gb2JqZWN0BXN0YWtlDHN0YWtpbmdfcG9vbANzdWkIdHJhbnNmZXIKdHhfY29udGV4dAl2YWxpZGF0b3INdmFsaWRhdG9yX3NldA5TdWlTeXN0ZW1TdGF0ZRBTeXN0ZW1QYXJhbWV0ZXJzCVR4Q29udGV4dA1hZHZhbmNlX2Vwb2NoCVZhbGlkYXRvcgZTdXBwbHkDU1VJB0JhbGFuY2UGY3JlYXRlBWVwb2NoBENvaW4WcmVxdWVzdF9hZGRfZGVsZWdhdGlvbgpMb2NrZWRDb2luJ3JlcXVlc3RfYWRkX2RlbGVnYXRpb25fd2l0aF9sb2NrZWRfY29pbhFyZXF1ZXN0X2FkZF9zdGFrZSJyZXF1ZXN0X2FkZF9zdGFrZV93aXRoX2xvY2tlZF9jb2luFXJlcXVlc3RfYWRkX3ZhbGlkYXRvchhyZXF1ZXN0X3JlbW92ZV92YWxpZGF0b3IVcmVxdWVzdF9zZXRfZ2FzX3ByaWNlCkRlbGVnYXRpb24JU3Rha2VkU3VpGXJlcXVlc3Rfc3dpdGNoX2RlbGVnYXRpb24bcmVxdWVzdF93aXRoZHJhd19kZWxlZ2F0aW9uBVN0YWtlFnJlcXVlc3Rfd2l0aGRyYXdfc3R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ABlE4AQEAA1I6BAEAEhYTFhQZFhwSIBggGBYZJBokGyAcIB0FHhYfIB0GIRYiJCMkJCQlJCYkJxYdNygkKRYhICogAwcIBQsGAQgHBwgIAAIIBQcICAEGCAABAwEIAAEIBAIGCAUDBAcIBQUDBwgIAgUDAQgFBAcIBQsGAQgHCwkBCAoHCAgBBggEAQYIBQEFAwcIBQgABwgEAwsGAQgHCwYBCAcLCQEICgUHCAIHCAQHCAADBwgIAwcIAAcIBAMCCwYBCAcLCQEICgUHCAUHCAAHCAQDBwgIBAcIBQcIAAcIBAMBCAcBBgsGAQkAAgcLBgEJAAsGAQkAAQgDAQYKCQABAQEIAgEHCAgBCAsBCQABCAEDCAsLBgEIAQMBCwYBCQADCAsLBgEIBwsJAQgKAQgKAQYLCQEJAAELCQEJAAIEAwEGCwwBCQAFBwgFAwgAAwsGAQgBAgcLDAEJAAMCCQAFAQsMAQkAAwUIBAMBBggIBAsGAQgHCwYBCAcLCQEICgMFCAoLBgEIBwsJAQgKCwYBCAcICgIHCwYBCQADAQcLCQEJAAEGCQAEBQsGAQgHCwYBCAcLCQEICgILBgEJAAcICAELDQEJAAELDQEIBwQLBgEJAAgKBQcICAoBBwgFAwMLBgEIBwsGAQgHAwQDCwkBCAoCBwsMAQkACwYBCQAJdmFsaWRhdG9yDXZhbGlkYXRvcl9zZXQMc3Rha2luZ19wb29sBm9wdGlvbgZ2ZWN0b3IHYmFsYW5jZQRjb2luD2Vwb2NoX3RpbWVfbG9jawtsb2NrZWRfY29pbgZvYmplY3QDc3VpCHRyYW5zZmVyCnR4X2NvbnRleHQKRGVsZWdhdGlvbg9EZWxlZ2F0aW9uVG9rZW4TSW5hY3RpdmVTdGFraW5nUG9vbBZQZW5kaW5nRGVsZWdhdGlvbkVudHJ5CVN0YWtlZFN1aQtTdGFraW5nUG9vbAdCYWxhbmNlA1NVSQlUeENvbnRleHQNYWR2YW5jZV9lcG9jaBdkZWFjdGl2YXRlX3N0YWtpbmdfcG9vbBdkZWxlZ2F0aW9uX3Rva2VuX2Ftb3VudBhkZXN0cm95X2VtcHR5X2RlbGVnYXRpb24YZGVzdHJveV9lbXB0eV9zdGFrZWRfc3VpDmdldF9zdWlfYW1vdW50EGdldF90b2tlbl9hbW91bnQjbWludF9kZWxlZ2F0aW9uX3Rva2Vuc190b19kZWxlZ2F0b3IDbmV3Bk9wdGlvbg1FcG9jaFRpbWVMb2NrFnJlcXVlc3RfYWRkX2RlbGVnYXRpb24Rc3Rha2VkX3N1aV9hbW91bnQLc3VpX2JhbGFuY2URdmFsaWRhdG9yX2FkZHJlc3Mad2l0aGRyYXdfYWxsX3RvX3N1aV90b2tlbnMbd2l0aGRyYXdfZnJvbV9pbmFjdGl2ZV9wb29sF3dpdGhkcmF3X2Zyb21fcHJpbmNpcGFsDndpdGhkcmF3X3N0YWtlFndpdGhkcmF3X3RvX3N1aV90b2tlbnMCaWQDVUlEE3Bvb2xfc3RhcnRpbmdfZXBvY2gLcG9vbF90b2tlbnMUcHJpbmNpcGFsX3N1aV9hbW91bnQLZHVtbXlfZmllbGQEcG9vbAlkZWxlZ2F0b3IKc3VpX2Ftb3VudAlwcmluY2lwYWwOc3VpX3Rva2VuX2xvY2sOc3RhcnRpbmdfZXBvY2gaZXBvY2hfc3RhcnRpbmdfc3VpX2JhbGFuY2UMcmV3YXJkc19wb29sF2RlbGVnYXRpb25fdG9rZW5fc3VwcGx5BlN1cHBseRNwZW5kaW5nX2RlbGVnYXRpb25zBXZhbHVlBGpvaW4IaXNfZW1wdHkMc2hhcmVfb2JqZWN0BmRlbGV0ZQxkZXN0cm95X3plcm8HaXNfbm9uZQxkZXN0cm95X25vbmUMc3VwcGx5X3ZhbHVlD2luY3JlYXNlX3N1cHBseQR6ZXJvDWNyZWF0ZV9zdXBwbHkGc2VuZGVyBXNwbGl0B2lzX3NvbWUHZXh0cmFjdAZib3Jyb3cEc29tZQRub25lBENvaW4MZnJvbV9iYWxhbmNlDGRlc3Ryb3lfc29tZRBuZXdfZnJvbV9iYWxhbmNlD2RlY3JlYXNlX3N1cHBseQAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAEDCAUAAAAAAAAAAwgAAAAAAAAAAAMIBAAAAAAAAAADCAMAAAAAAAAAAwgGAAAAAAAAAAMIAgAAAAAAAAADCAEAAAAAAAAAAAIFKggLJAUsAy0LBgEIAS4DAQIBLwECAgIqCAswCAUDAgIxBTIDBAIDKggLMwsGAQgHNAsJAQgKBQIHJAU1AzYDIwM3CwYBCAc4CwwBCAE6CggDAAM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IAwsGAQgHBwgEAgcIAAgBAgcIAAYIBAMHCAADBwgEBQcIAAgIBwgJBQcIBAUHCAAHCAgHCAkDBwgEBQcIAAcICgMDBwgEAQcKAwMDAwcIAQEIAQUDCgMDCgMDAQgDAQYLAgEJAAIDAwYDAwMDBggBAwoEBAQKAwMDBAQGCAEKAwMDAwYIAQIGCAEGCAEIAwMGCAUGCAUDAwMKCAUBCAUBBggFCwoLCwEDAwMDCwwBAwMDAwMGCAEGCggBAQsLAQMCAwkAAQsLAQkAAQoLCwEJAAELDAEJAAEHCwwBCQAHCwIBCAMDAwMLAgEIAwMHCAECBwsCAQkAAwELAgEJAAEIBwELBgEJAAQHCAELAgEIAwsGAQgHBwgEAwcIAQsCAQgDBwgEAQUBCQAEBwoIAQUDCwYBAwEGCwYBCQABBwsGAQkAAgMLBgEDBAMDAwgAAgMIAQEGCgkAAgcKCQADAggBBwgEAgcIAQUBBggEAwUDCwYBAwIGCgkABgkAAgcIAQMIBwgBBQMLBgEDCwIBCAMLAgEIAwsGAQgHAwEGCAgBBwgNAwcIDQgIBwgJAwsCAQgDCwIBCAMLBgEIBwQHCAEFAwsGAQMFBwgBBwgIBwgJAwcIBAUHCAEHCAoDAwcIBAgHCgMDBwoDAwMDAwMKc3VpX3N5c3RlbQ12YWxpZGF0b3Jfc2V0Bm9wdGlvbgZ2ZWN0b3IHYmFsYW5jZQ9lcG9jaF90aW1lX2xvY2sOcHJpb3JpdHlfcXVldWUFc3Rha2UMc3Rha2luZ19wb29sA3N1aQp0eF9jb250ZXh0CXZhbGlkYXRvcgxWYWxpZGF0b3JTZXQJVmFsaWRhdG9yGmFkanVzdF9zdGFrZV9hbmRfZ2FzX3ByaWNlB0JhbGFuY2UDU1VJCVR4Q29udGV4dA1hZHZhbmNlX2Vwb2NoGmNhbGN1bGF0ZV9xdW9ydW1fdGhyZXNob2xkKmNhbGN1bGF0ZV90b3RhbF9zdGFrZV9hbmRfcXVvcnVtX3RocmVzaG9sZBtjb21wdXRlX3Jld2FyZF9kaXN0cmlidXRpb24cY29udGFpbnNfZHVwbGljYXRlX3ZhbGlkYXRvchFWYWxpZGF0b3JNZXRhZGF0YRxkZXJpdmVfbmV4dF9lcG9jaF92YWxpZGF0b3JzGmRlcml2ZV9yZWZlcmVuY2VfZ2FzX3ByaWNlEWRpc3RyaWJ1dGVfcmV3YXJkBk9wdGlvbg5maW5kX3ZhbGlkYXRvchFnZXRfdmFsaWRhdG9yX211dBFnZXRfdmFsaWRhdG9yX3JlZhNpc19hY3RpdmVfdmFsaWRhdG9yA25ldxpuZXh0X2Vwb2NoX3ZhbGlkYXRvcl9jb3VudBhwcm9jZXNzX3BlbmRpbmdfcmVtb3ZhbHMacHJvY2Vzc19wZW5kaW5nX3ZhbGlkYXRvcnMNRXBvY2hUaW1lTG9jaxZyZXF1ZXN0X2FkZF9kZWxlZ2F0aW9uEXJlcXVlc3RfYWRkX3N0YWtlFXJlcXVlc3RfYWRkX3ZhbGlkYXRvchhyZXF1ZXN0X3JlbW92ZV92YWxpZGF0b3IVcmVxdWVzdF9zZXRfZ2FzX3ByaWNlCkRlbGVnYXRpb24JU3Rha2VkU3VpGXJlcXVlc3Rfc3dpdGNoX2RlbGVnYXRpb24bcmVxdWVzdF93aXRoZHJhd19kZWxlZ2F0aW9uBVN0YWtlFnJlcXVlc3Rfd2l0aGRyYXdfc3Rha2URc29ydF9yZW1vdmFsX2xpc3QWdG90YWxfZGVsZWdhdGlvbl9zdGFrZRV0b3RhbF92YWxpZGF0b3Jfc3Rha2UZdmFsaWRhdG9yX2RlbGVnYXRlX2Ftb3VudBZ2YWxpZGF0b3Jfc3Rha2VfYW1vdW50FnF1b3J1bV9zdGFrZV90aHJlc2hvbGQRYWN0aXZlX3ZhbGlkYXRvcnMScGVuZGluZ192YWxpZGF0b3JzEHBlbmRpbmdfcmVtb3ZhbHMVbmV4dF9lcG9jaF92YWxpZGF0b3JzBXZhbHVlDHN0YWtlX2Ftb3VudA9kZWxlZ2F0ZV9hbW91bnQMaXNfZHVwbGljYXRlCG1ldGFkYXRhBUVudHJ5DVByaW9yaXR5UXVldWUJZ2FzX3ByaWNlCW5ld19lbnRyeQdwb3BfbWF4BXNwbGl0BG5vbmUmZGlzdHJpYnV0ZV9yZXdhcmRzX2FuZF9uZXdfZGVsZWdhdGlvbnMLc3VpX2FkZHJlc3MEc29tZQdpc19zb21lB2V4dHJhY3QIaXNfZW1wdHkGcmVtb3ZlB2Rlc3Ryb3kGc2VuZGVyCGNvbnRhaW5zEXZhbGlkYXRvcl9hZGRyZXNzC1N0YWtpbmdQb29sGGdldF9zdGFraW5nX3Bvb2xfbXV0X3J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 diff --git a/crates/sui-config/tests/snapshots/snapshot_tests__populated_genesis_snapshot_matches-5.snap b/crates/sui-config/tests/snapshots/snapshot_tests__populated_genesis_snapshot_matches-5.snap index 268a340b84b55..16aebf20a582f 100644 --- a/crates/sui-config/tests/snapshots/snapshot_tests__populated_genesis_snapshot_matches-5.snap +++ b/crates/sui-config/tests/snapshots/snapshot_tests__populated_genesis_snapshot_matches-5.snap @@ -210,15 +210,19 @@ validators: next_epoch_delegation: 0 next_epoch_gas_price: 1 stake_amount: 1 - delegation: 0 pending_stake: 0 pending_withdraw: 0 - pending_delegation: 0 - pending_delegation_withdraw: 0 - delegator_count: 0 - pending_delegator_count: 0 - pending_delegator_withdraw_count: 0 gas_price: 1 + delegation_staking_pool: + validator_address: 375741c9373ae27bde5e6b5f5cc79f074cd84587 + starting_epoch: 1 + epoch_starting_sui_balance: 0 + sui_balance: 0 + rewards_pool: + value: 0 + delegation_token_supply: + value: 0 + pending_delegations: [] pending_validators: [] pending_removals: [] next_epoch_validators: @@ -428,7 +432,5 @@ parameters: min_validator_stake: 100000000000000 max_validator_candidate_count: 100 storage_gas_price: 1 -delegation_reward: - value: 0 reference_gas_price: 0 diff --git a/crates/sui-cost/tests/snapshots/empirical_transaction_cost__good_snapshot.snap b/crates/sui-cost/tests/snapshots/empirical_transaction_cost__good_snapshot.snap index 9ec1f968eb1ef..3f7f203b61178 100644 --- a/crates/sui-cost/tests/snapshots/empirical_transaction_cost__good_snapshot.snap +++ b/crates/sui-cost/tests/snapshots/empirical_transaction_cost__good_snapshot.snap @@ -4,12 +4,12 @@ expression: common_costs --- { "MergeCoin": { - "computation_cost": 466, + "computation_cost": 482, "storage_cost": 32, "storage_rebate": 0 }, "Publish": { - "computation_cost": 524, + "computation_cost": 541, "storage_cost": 83, "storage_rebate": 0 }, @@ -29,7 +29,7 @@ expression: common_costs "storage_rebate": 15 }, "SplitCoin": { - "computation_cost": 577, + "computation_cost": 593, "storage_cost": 80, "storage_rebate": 0 }, diff --git a/crates/sui-framework/sources/epoch_time_lock.move b/crates/sui-framework/sources/epoch_time_lock.move index b7ac21a8342c1..5181c12d1f5ce 100644 --- a/crates/sui-framework/sources/epoch_time_lock.move +++ b/crates/sui-framework/sources/epoch_time_lock.move @@ -12,7 +12,7 @@ module sui::epoch_time_lock { /// Holder of an epoch number that can only be discarded in the epoch or /// after the epoch has passed. - struct EpochTimeLock has store { + struct EpochTimeLock has store, copy { epoch: u64 } diff --git a/crates/sui-framework/sources/governance/delegation.move b/crates/sui-framework/sources/governance/delegation.move deleted file mode 100644 index 66d98917ffe8a..0000000000000 --- a/crates/sui-framework/sources/governance/delegation.move +++ /dev/null @@ -1,207 +0,0 @@ -// Copyright (c) 2022, Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module sui::delegation { - use std::option::{Self, Option}; - use sui::balance::{Self, Balance}; - use sui::coin::{Self, Coin}; - use sui::object::{Self, UID}; - use sui::locked_coin::{Self, LockedCoin}; - use sui::sui::SUI; - use sui::transfer; - use sui::tx_context::{Self, TxContext}; - use sui::epoch_time_lock::EpochTimeLock; - - friend sui::sui_system; - - /// A custodial delegation object. When the delegation is active, the delegation - /// object holds the delegated stake coin. It also contains the delegation - /// target validator address. - /// The delegation object is required to claim delegation reward. The object - /// keeps track of the next reward unclaimed epoch. One can only claim reward - /// for the epoch that matches the `next_reward_unclaimed_epoch`. - /// When the delegation is deactivated, we keep track of the ending epoch - /// so that we know the ending epoch that the delegator can still claim reward. - struct Delegation has key { - id: UID, - /// The delegated stake, if the delegate is still active - active_delegation: Option>, - /// If the delegation is inactive, `ending_epoch` will be - /// set to the ending epoch, i.e. the epoch when the delegation - /// was withdrawn. Delegator will not be eligible to claim reward - /// for ending_epoch and after. - ending_epoch: Option, - /// The delegated stake amount. - delegate_amount: u64, - /// Delegator is able to claim reward epoch by epoch. `next_reward_unclaimed_epoch` - /// is the next epoch that the delegator can claim epoch. Whenever the delegator - /// claims reward for an epoch, this value increments by one. - next_reward_unclaimed_epoch: u64, - /// The epoch until which the delegated coin is locked. If the delegated stake - /// comes from a Coin, this field is None. If it comes from a LockedCoin, this - /// field is not None, and after undelegation the stake will be returned to a LockedCoin - /// with locked_until_epoch set to this epoch. - coin_locked_until_epoch: Option, - /// The delegation target validator. - validator_address: address, - } - - public(friend) fun create( - starting_epoch: u64, - validator_address: address, - stake: Coin, - ctx: &mut TxContext, - ) { - let delegate_amount = coin::value(&stake); - let delegation = Delegation { - id: object::new(ctx), - active_delegation: option::some(coin::into_balance(stake)), - ending_epoch: option::none(), - delegate_amount, - next_reward_unclaimed_epoch: starting_epoch, - coin_locked_until_epoch: option::none(), - validator_address, - }; - transfer::transfer(delegation, tx_context::sender(ctx)) - } - - public(friend) fun create_from_locked_coin( - starting_epoch: u64, - validator_address: address, - stake: LockedCoin, - ctx: &mut TxContext, - ) { - let delegate_amount = locked_coin::value(&stake); - let (balance, epoch_lock) = locked_coin::into_balance(stake); - let delegation = Delegation { - id: object::new(ctx), - active_delegation: option::some(balance), - ending_epoch: option::none(), - delegate_amount, - next_reward_unclaimed_epoch: starting_epoch, - coin_locked_until_epoch: option::some(epoch_lock), - validator_address, - }; - transfer::transfer(delegation, tx_context::sender(ctx)) - } - - /// Deactivate the delegation. Send back the stake and set the ending epoch. - public(friend) fun undelegate( - self: &mut Delegation, - ending_epoch: u64, - ctx: &mut TxContext, - ) { - assert!(is_active(self), 0); - assert!(ending_epoch >= self.next_reward_unclaimed_epoch, 0); - - let stake = option::extract(&mut self.active_delegation); - let sender = tx_context::sender(ctx); - - if (option::is_none(&self.coin_locked_until_epoch)) { - transfer::transfer(coin::from_balance(stake, ctx), sender); - } else { - let locked_until_epoch = option::extract(&mut self.coin_locked_until_epoch); - locked_coin::new_from_balance(stake, locked_until_epoch, sender, ctx); - }; - - self.ending_epoch = option::some(ending_epoch); - } - - /// Switch the delegation from the current validator to `new_validator_address`. - /// The current `Delegation` object `self` becomes inactive and the balance inside is - /// extracted to the new `Delegation` object. - public(friend) fun switch_delegation( - self: &mut Delegation, - new_validator_address: address, - ctx: &mut TxContext, - ) { - assert!(is_active(self), 0); - let current_epoch = tx_context::epoch(ctx); - let balance = option::extract(&mut self.active_delegation); - let delegate_amount = balance::value(&balance); - - let new_epoch_lock = - if (option::is_some(&self.coin_locked_until_epoch)) { - option::some(option::extract(&mut self.coin_locked_until_epoch)) - } else { - option::none() - }; - - self.ending_epoch = option::some(current_epoch); - - let new_delegation = Delegation { - id: object::new(ctx), - active_delegation: option::some(balance), - ending_epoch: option::none(), - delegate_amount, - next_reward_unclaimed_epoch: current_epoch + 1, - coin_locked_until_epoch: new_epoch_lock, - validator_address: new_validator_address, - }; - transfer::transfer(new_delegation, tx_context::sender(ctx)) - } - - /// Claim delegation reward. Increment next_reward_unclaimed_epoch. - public(friend) fun claim_reward( - self: &mut Delegation, - reward: Balance, - ctx: &mut TxContext, - ) { - let sender = tx_context::sender(ctx); - transfer::transfer(coin::from_balance(reward, ctx), sender); - self.next_reward_unclaimed_epoch = self.next_reward_unclaimed_epoch + 1; - } - - - /// Destroy the delegation object. This can be done only when the delegation - /// is inactive and all reward have been claimed. - public entry fun burn(self: Delegation) { - assert!(!is_active(&self), 0); - - let Delegation { - id, - active_delegation, - ending_epoch, - delegate_amount: _, - next_reward_unclaimed_epoch, - coin_locked_until_epoch, - validator_address: _, - } = self; - object::delete(id); - option::destroy_none(active_delegation); - option::destroy_none(coin_locked_until_epoch); - let ending_epoch = *option::borrow(&ending_epoch); - assert!(next_reward_unclaimed_epoch == ending_epoch, 0); - } - - /// Checks whether the delegation object is eligible to claim the reward - /// given the epoch to claim and the validator address. - public fun can_claim_reward( - self: &Delegation, - epoch_to_claim: u64, - validator: address, - ): bool { - if (validator != self.validator_address || - self.next_reward_unclaimed_epoch > epoch_to_claim) - { - return false - }; - if (!is_active(self)) { - let ending_epoch = *option::borrow(&self.ending_epoch); - return ending_epoch > epoch_to_claim - }; - true - } - - public fun validator(self: &Delegation): address { - self.validator_address - } - - public fun delegate_amount(self: &Delegation): u64 { - self.delegate_amount - } - - public fun is_active(self: &Delegation): bool { - option::is_some(&self.active_delegation) && option::is_none(&self.ending_epoch) - } -} diff --git a/crates/sui-framework/sources/governance/epoch_reward_record.move b/crates/sui-framework/sources/governance/epoch_reward_record.move deleted file mode 100644 index b9aa791336cf7..0000000000000 --- a/crates/sui-framework/sources/governance/epoch_reward_record.move +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) 2022, Mysten Labs, Inc. -// SPDX-License-Identifier: Apache-2.0 - -module sui::epoch_reward_record { - use sui::object::{Self, UID}; - use sui::transfer; - use sui::tx_context::TxContext; - - friend sui::sui_system; - friend sui::validator_set; - - /// EpochRewardRecord is an immutable record created per epoch per active validator. - /// Sufficient information is saved in the record so that delegators can claim - /// delegation rewards from past epochs, and for validators that may no longer be active. - /// TODO: For now we assume that validators don't charge an extra fee. - /// Delegation reward is simply proportional to to overall delegation reward ratio - /// and the delegation amount. - struct EpochRewardRecord has key { - id: UID, - epoch: u64, - computation_charge: u64, - total_stake: u64, - delegator_count: u64, - validator: address, - } - - public(friend) fun create( - epoch: u64, - computation_charge: u64, - total_stake: u64, - delegator_count: u64, - validator: address, - ctx: &mut TxContext, - ) { - transfer::share_object(EpochRewardRecord { - id: object::new(ctx), - epoch, - computation_charge, - total_stake, - delegator_count, - validator, - }) - } - - /// Given the delegation amount, calculate the reward, and decrement the `delegator_count`. - public(friend) fun claim_reward(self: &mut EpochRewardRecord, delegation_amount: u64): u64 { - self.delegator_count = self.delegator_count - 1; - // TODO: Once self.delegator_count reaches 0, we should be able to delete this object. - delegation_amount * self.computation_charge / self.total_stake - } - - public fun epoch(self: &EpochRewardRecord): u64 { - self.epoch - } - - public fun validator(self: &EpochRewardRecord): address { - self.validator - } -} diff --git a/crates/sui-framework/sources/governance/staking_pool.move b/crates/sui-framework/sources/governance/staking_pool.move new file mode 100644 index 0000000000000..25d3a7dfb99ae --- /dev/null +++ b/crates/sui-framework/sources/governance/staking_pool.move @@ -0,0 +1,343 @@ +// Copyright (c) 2022, Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +module sui::staking_pool { + use sui::balance::{Self, Balance, Supply}; + use sui::sui::SUI; + use std::option::{Self, Option}; + use sui::tx_context::{Self, TxContext}; + use sui::transfer; + use sui::epoch_time_lock::{EpochTimeLock}; + use sui::object::{Self, UID}; + use sui::locked_coin; + use sui::coin; + use std::vector; + + friend sui::validator; + friend sui::validator_set; + + const EINSUFFICIENT_POOL_TOKEN_BALANCE: u64 = 0; + const EWRONG_POOL: u64 = 1; + const EWITHDRAW_AMOUNT_CANNOT_BE_ZERO: u64 = 2; + const EINSUFFICIENT_SUI_TOKEN_BALANCE: u64 = 3; + const EINSUFFICIENT_REWARDS_POOL_BALANCE: u64 = 4; + const EDESTROY_NON_ZERO_BALANCE: u64 = 5; + const ETOKEN_TIME_LOCK_IS_SOME: u64 = 6; + + /// A staking pool embedded in each validator struct in the system state object. + struct StakingPool has store { + /// The sui address of the validator associated with this pool. + validator_address: address, + /// The epoch at which this pool started operating. Should be the epoch at which the validator became active. + starting_epoch: u64, + /// The total number of SUI tokens in this pool at the beginning of the current epoch. + epoch_starting_sui_balance: u64, + /// The total number of SUI tokens in this pool, including the SUI in the rewards_pool, as well as in all the principal + /// in the `Delegation` object. + sui_balance: u64, + /// The epoch delegation rewards will be added here at the end of each epoch. + rewards_pool: Balance, + /// The number of delegation pool tokens we have issued so far. This number should equal the sum of + /// pool token balance in all the `Delegation` objects delegated to this pool. + delegation_token_supply: Supply, + /// Delegations requested during the current epoch. We will activate these delegation at the end of current epoch + /// and distribute staking pool tokens at the end-of-epoch exchange rate after the rewards for the current epoch + /// have been deposited. + pending_delegations: vector, + } + + /// An inactive staking pool associated with an inactive validator. + /// Only withdraws can be made from this pool. + struct InactiveStakingPool has key { + id: UID, // TODO: inherit an ID from active staking pool? + pool: StakingPool, + } + + /// The staking pool token. + struct DelegationToken has drop {} + + /// Struct representing a pending delegation. + struct PendingDelegationEntry has store, drop { + delegator: address, + sui_amount: u64, + } + + /// A self-custodial delegation object, serving as evidence that the delegator + /// has delegated to a staking pool. + struct Delegation has key { + id: UID, + /// The sui address of the validator associated with the staking pool this object delgates to. + validator_address: address, + /// The epoch at which the staking pool started operating. + pool_starting_epoch: u64, + /// The pool tokens representing the amount of rewards the delegator can get back when they withdraw + /// from the pool. If this field is `none`, that means the delegation hasn't been activated yet. + pool_tokens: Balance, + /// Number of SUI token staked originally. + principal_sui_amount: u64, + } + + /// A self-custodial object holding the staked SUI tokens. + struct StakedSui has key { + id: UID, + /// The staked SUI tokens. + principal: Balance, + /// If the stake comes from a Coin, this field is None. If it comes from a LockedCoin, this + /// field will record the original lock expiration epoch, to be used when unstaking. + sui_token_lock: Option, + } + + /// Create a new, empty staking pool. + public(friend) fun new(validator_address: address, starting_epoch: u64) : StakingPool { + StakingPool { + validator_address, + starting_epoch, + epoch_starting_sui_balance: 0, + sui_balance: 0, + rewards_pool: balance::zero(), + delegation_token_supply: balance::create_supply(DelegationToken {}), + pending_delegations: vector::empty(), + } + } + + /// Called at epoch advancement times to add rewards (in SUI) to the staking pool, and distribute new delegation tokens. + public(friend) fun advance_epoch(pool: &mut StakingPool, rewards: Balance, ctx: &mut TxContext) { + pool.sui_balance = pool.sui_balance + balance::value(&rewards); + balance::join(&mut pool.rewards_pool, rewards); + + // distribute pool tokens at new exchange rate. + while (!vector::is_empty(&pool.pending_delegations)) { + let PendingDelegationEntry { delegator, sui_amount } = vector::pop_back(&mut pool.pending_delegations); + mint_delegation_tokens_to_delegator(pool, delegator, sui_amount, ctx); + pool.sui_balance = pool.sui_balance + sui_amount + }; + + // Record the epoch starting balance. + pool.epoch_starting_sui_balance = pool.sui_balance; + } + + // TODO: implement rate limiting new delegations per epoch. + /// Request to delegate to a staking pool. The delegation gets counted at the beginning of the next epoch, + /// when the delegation object containing the pool tokens is distributed to the delegator. + public(friend) fun request_add_delegation( + pool: &mut StakingPool, + stake: Balance, + sui_token_lock: Option, + ctx: &mut TxContext + ) { + let sui_amount = balance::value(&stake); + assert!(sui_amount > 0, 0); + let delegator = tx_context::sender(ctx); + // insert delegation info into the pendng_delegations vector. + vector::push_back(&mut pool.pending_delegations, PendingDelegationEntry { delegator, sui_amount }); + let staked_sui = StakedSui { + id: object::new(ctx), + principal: stake, + sui_token_lock, + }; + transfer::transfer(staked_sui, delegator); + } + + /// Activate a delegation. New pool tokens are minted at the current exchange rate and put into the + /// `pool_tokens` field of the delegation object. + /// After activation, the delegation officially counts toward the staking power of the validator. + /// Aborts if the pool mismatches, the delegation is already activated, or the delegation cannot be activated yet. + public(friend) fun mint_delegation_tokens_to_delegator( + pool: &mut StakingPool, + delegator: address, + sui_amount: u64, + ctx: &mut TxContext + ) { + let new_pool_token_amount = get_token_amount(pool, sui_amount); + + // Mint new pool tokens at the current exchange rate. + let pool_tokens = balance::increase_supply(&mut pool.delegation_token_supply, new_pool_token_amount); + + let delegation = Delegation { + id: object::new(ctx), + validator_address: pool.validator_address, + pool_starting_epoch: pool.starting_epoch, + pool_tokens, + principal_sui_amount: sui_amount, + }; + + transfer::transfer(delegation, delegator); + } + + /// Withdraw `withdraw_pool_token_amount` worth of delegated stake from a staking pool. A proportional amount of principal and rewards + /// in SUI will be withdrawn and transferred to the delegator. + public(friend) fun withdraw_stake( + pool: &mut StakingPool, + delegation: &mut Delegation, + staked_sui: &mut StakedSui, + withdraw_pool_token_amount: u64, + ctx: &mut TxContext + ) { + let (principal_withdraw, reward_withdraw, time_lock) = + withdraw_to_sui_tokens(pool, delegation, staked_sui, withdraw_pool_token_amount); + + let delegator = tx_context::sender(ctx); + + // TODO: implement withdraw bonding period here. + transfer::transfer(coin::from_balance(reward_withdraw, ctx), delegator); + + if (option::is_some(&time_lock)) { + locked_coin::new_from_balance(principal_withdraw, option::destroy_some(time_lock), delegator, ctx); + } else { + transfer::transfer(coin::from_balance(principal_withdraw, ctx), delegator); + option::destroy_none(time_lock); + } + } + + /// Withdraw all the pool tokens in `delegation` object, with separate principal and rewards components, and + /// then destroy the delegation object. + public(friend) fun withdraw_all_to_sui_tokens( + pool: &mut StakingPool, + delegation: Delegation, + staked_sui: &mut StakedSui, + ) : (Balance, Balance, Option) { + let withdraw_amount = balance::value(&delegation.pool_tokens); + let (principal_withdraw, reward_withdraw, time_lock) = + withdraw_to_sui_tokens(pool, &mut delegation, staked_sui, withdraw_amount); + destroy_empty_delegation(delegation); + (principal_withdraw, reward_withdraw, time_lock) + } + + fun withdraw_to_sui_tokens( + pool: &mut StakingPool, + delegation: &mut Delegation, + staked_sui: &mut StakedSui, + withdraw_pool_token_amount: u64, + ) : (Balance, Balance, Option) { + assert!( + delegation.validator_address == pool.validator_address && + delegation.pool_starting_epoch == pool.starting_epoch, + EWRONG_POOL + ); + + assert!(withdraw_pool_token_amount > 0, EWITHDRAW_AMOUNT_CANNOT_BE_ZERO); + + let pool_token_balance = balance::value(&delegation.pool_tokens); + assert!(pool_token_balance >= withdraw_pool_token_amount, EINSUFFICIENT_POOL_TOKEN_BALANCE); + + // Calculate the amount of SUI tokens that should be withdrawn from the pool using the current exchange rate. + let sui_withdraw_amount = get_sui_amount(pool, withdraw_pool_token_amount); + + // decrement sui balance in the pool + pool.sui_balance = pool.sui_balance - sui_withdraw_amount; + + // Calculate the amounts of SUI to be withdrawn from the principal component and the rewards component. + // We already checked that pool_token_balance is greater than zero. + let sui_withdraw_from_principal = + (delegation.principal_sui_amount as u128) * (withdraw_pool_token_amount as u128) / (pool_token_balance as u128); + let sui_withdraw_from_rewards = sui_withdraw_amount - (sui_withdraw_from_principal as u64); + + // burn the pool tokens + balance::decrease_supply( + &mut pool.delegation_token_supply, + balance::split(&mut delegation.pool_tokens, withdraw_pool_token_amount) + ); + + let (principal_withdraw, time_lock) = withdraw_from_principal(delegation, staked_sui, (sui_withdraw_from_principal as u64)); + + // withdraw the rewards component from rewards pool and transfer it to the delegator. + assert!(balance::value(&pool.rewards_pool) >= sui_withdraw_from_rewards, EINSUFFICIENT_REWARDS_POOL_BALANCE); + let reward_withdraw = balance::split(&mut pool.rewards_pool, sui_withdraw_from_rewards); + pool.sui_balance = pool.sui_balance - sui_withdraw_from_rewards; + + (principal_withdraw, reward_withdraw, time_lock) + } + + /// Deactivate a staking pool by wrapping it in an `InactiveStakingPool` and sharing this newly created object. + /// After this pool deactivation, the pool stops earning rewards. Only delegation withdraws can be made to the pool. + public(friend) fun deactivate_staking_pool(pool: StakingPool, ctx: &mut TxContext) { + let inactive_pool = InactiveStakingPool { id: object::new(ctx), pool}; + transfer::share_object(inactive_pool); + } + + /// Withdraw delegation from an inactive pool. + public entry fun withdraw_from_inactive_pool( + inactive_pool: &mut InactiveStakingPool, + staked_sui: &mut StakedSui, + delegation: &mut Delegation, + withdraw_amount: u64, + ctx: &mut TxContext + ) { + withdraw_stake(&mut inactive_pool.pool, delegation, staked_sui, withdraw_amount, ctx); + } + + /// Destroy an empty delegation that no longer contains any SUI or pool tokens. + public entry fun destroy_empty_delegation(delegation: Delegation) { + let Delegation { + id, + validator_address: _, + pool_starting_epoch: _, + pool_tokens, + principal_sui_amount, + } = delegation; + object::delete(id); + assert!(balance::value(&pool_tokens) == 0, EDESTROY_NON_ZERO_BALANCE); + assert!(principal_sui_amount == 0, EDESTROY_NON_ZERO_BALANCE); + balance::destroy_zero(pool_tokens); + } + + /// Destroy an empty delegation that no longer contains any SUI or pool tokens. + public entry fun destroy_empty_staked_sui(staked_sui: StakedSui) { + let StakedSui { + id, + principal, + sui_token_lock + } = staked_sui; + object::delete(id); + assert!(balance::value(&principal) == 0, EDESTROY_NON_ZERO_BALANCE); + balance::destroy_zero(principal); + assert!(option::is_none(&sui_token_lock), ETOKEN_TIME_LOCK_IS_SOME); + option::destroy_none(sui_token_lock); + } + + public fun sui_balance(pool: &StakingPool) : u64 { pool.epoch_starting_sui_balance } + + public fun validator_address(delegation: &Delegation) : address { delegation.validator_address } + + public fun staked_sui_amount(staked_sui: &StakedSui): u64 { balance::value(&staked_sui.principal) } + + public fun delegation_token_amount(delegation: &Delegation): u64 { balance::value(&delegation.pool_tokens) } + + /// Withdraw `withdraw_amount` of SUI tokens from the delegation and give it back to the delegator + /// in the original state of the tokens. + fun withdraw_from_principal( + delegation: &mut Delegation, + staked_sui: &mut StakedSui, + withdraw_amount: u64, + ) : (Balance, Option) { + assert!(balance::value(&staked_sui.principal) >= withdraw_amount, EINSUFFICIENT_SUI_TOKEN_BALANCE); + delegation.principal_sui_amount = delegation.principal_sui_amount - withdraw_amount; + let principal_withdraw = balance::split(&mut staked_sui.principal, withdraw_amount); + if (option::is_some(&staked_sui.sui_token_lock)) { + let time_lock = + if (balance::value(&staked_sui.principal) == 0) {option::extract(&mut staked_sui.sui_token_lock)} + else *option::borrow(&staked_sui.sui_token_lock); + (principal_withdraw, option::some(time_lock)) + } else { + (principal_withdraw, option::none()) + } + } + + fun get_sui_amount(pool: &StakingPool, token_amount: u64): u64 { + let token_supply_amount = balance::supply_value(&pool.delegation_token_supply); + if (token_supply_amount == 0) { + return token_amount + }; + let res = (pool.sui_balance as u128) * (token_amount as u128) / (token_supply_amount as u128); + (res as u64) + } + + fun get_token_amount(pool: &StakingPool, sui_amount: u64): u64 { + let token_supply_amount = balance::supply_value(&pool.delegation_token_supply); + if (pool.sui_balance == 0) { + return sui_amount + }; + let res = (token_supply_amount as u128) * (sui_amount as u128) / (pool.sui_balance as u128); + (res as u64) + } +} diff --git a/crates/sui-framework/sources/governance/sui_system.move b/crates/sui-framework/sources/governance/sui_system.move index 9fbab90ecec96..4fac5f3b97095 100644 --- a/crates/sui-framework/sources/governance/sui_system.move +++ b/crates/sui-framework/sources/governance/sui_system.move @@ -4,8 +4,7 @@ module sui::sui_system { use sui::balance::{Self, Balance, Supply}; use sui::coin::{Self, Coin}; - use sui::delegation::{Self, Delegation}; - use sui::epoch_reward_record::{Self, EpochRewardRecord}; + use sui::staking_pool::{Delegation, StakedSui}; use sui::object::{Self, UID}; use sui::locked_coin::{Self, LockedCoin}; use sui::sui::SUI; @@ -50,9 +49,6 @@ module sui::sui_system { storage_fund: Balance, /// A list of system config parameters. parameters: SystemParameters, - /// The delegation reward pool. All delegation reward goes into this. - /// Delegation reward claims withdraw from this. - delegation_reward: Balance, /// The reference gas price for the current epoch. reference_gas_price: u64, } @@ -83,7 +79,6 @@ module sui::sui_system { max_validator_candidate_count, storage_gas_price }, - delegation_reward: balance::zero(), reference_gas_price, }; transfer::share_object(state); @@ -216,12 +211,13 @@ module sui::sui_system { validator_address: address, ctx: &mut TxContext, ) { - let amount = coin::value(&delegate_stake); - validator_set::request_add_delegation(&mut self.validators, validator_address, amount); - - // Delegation starts from the next epoch. - let starting_epoch = self.epoch + 1; - delegation::create(starting_epoch, validator_address, delegate_stake, ctx); + validator_set::request_add_delegation( + &mut self.validators, + validator_address, + coin::into_balance(delegate_stake), + option::none(), + ctx, + ); } public entry fun request_add_delegation_with_locked_coin( @@ -230,59 +226,35 @@ module sui::sui_system { validator_address: address, ctx: &mut TxContext, ) { - let amount = locked_coin::value(&delegate_stake); - validator_set::request_add_delegation(&mut self.validators, validator_address, amount); - - // Delegation starts from the next epoch. - let starting_epoch = self.epoch + 1; - delegation::create_from_locked_coin(starting_epoch, validator_address, delegate_stake, ctx); + let (balance, lock) = locked_coin::into_balance(delegate_stake); + validator_set::request_add_delegation(&mut self.validators, validator_address, balance, option::some(lock), ctx); } - public entry fun request_remove_delegation( + public entry fun request_withdraw_delegation( self: &mut SuiSystemState, delegation: &mut Delegation, + staked_sui: &mut StakedSui, + withdraw_amount: u64, ctx: &mut TxContext, ) { - validator_set::request_remove_delegation( + validator_set::request_withdraw_delegation( &mut self.validators, - delegation::validator(delegation), - delegation::delegate_amount(delegation), + delegation, + staked_sui, + withdraw_amount, + ctx, ); - delegation::undelegate(delegation, self.epoch, ctx) } // Switch delegation from the current validator to a new one. public entry fun request_switch_delegation( self: &mut SuiSystemState, - delegation: &mut Delegation, + delegation: Delegation, + staked_sui: &mut StakedSui, new_validator_address: address, ctx: &mut TxContext, ) { - let old_validator_address = delegation::validator(delegation); - let amount = delegation::delegate_amount(delegation); - validator_set::request_remove_delegation(&mut self.validators, old_validator_address, amount); - validator_set::request_add_delegation(&mut self.validators, new_validator_address, amount); - delegation::switch_delegation(delegation, new_validator_address, ctx); - } - - // TODO: Once we support passing vector of object references as arguments, - // we should support passing a vector of &mut EpochRewardRecord, - // which will allow delegators to claim all their reward in one transaction. - public entry fun claim_delegation_reward( - self: &mut SuiSystemState, - delegation: &mut Delegation, - epoch_reward_record: &mut EpochRewardRecord, - ctx: &mut TxContext, - ) { - let epoch = epoch_reward_record::epoch(epoch_reward_record); - let validator = epoch_reward_record::validator(epoch_reward_record); - assert!(delegation::can_claim_reward(delegation, epoch, validator), 0); - let reward_amount = epoch_reward_record::claim_reward( - epoch_reward_record, - delegation::delegate_amount(delegation), - ); - let reward = balance::split(&mut self.delegation_reward, reward_amount); - delegation::claim_reward(delegation, reward, ctx); + validator_set::request_switch_delegation(&mut self.validators, delegation, staked_sui, new_validator_address, ctx); } /// This function should be called at the end of an epoch, and advances the system to the next epoch. @@ -312,15 +284,6 @@ module sui::sui_system { let delegator_reward_amount = delegation_stake * computation_charge / total_stake; let delegator_reward = balance::split(&mut computation_reward, delegator_reward_amount); balance::join(&mut self.storage_fund, storage_reward); - balance::join(&mut self.delegation_reward, delegator_reward); - - validator_set::create_epoch_records( - &self.validators, - self.epoch, - computation_charge, - total_stake, - ctx, - ); self.epoch = self.epoch + 1; // Sanity check to make sure we are advancing to the right epoch. @@ -328,12 +291,15 @@ module sui::sui_system { validator_set::advance_epoch( &mut self.validators, &mut computation_reward, + &mut delegator_reward, ctx, ); // Derive the reference gas price for the new epoch self.reference_gas_price = validator_set::derive_reference_gas_price(&self.validators); // Because of precision issues with integer divisions, we expect that there will be some - // remaining balance in `computation_reward`. All of these go to the storage fund. + // remaining balance in `delegator_reward` and `computation_reward`. All of these go to + // the storage fund. + balance::join(&mut self.storage_fund, delegator_reward); balance::join(&mut self.storage_fund, computation_reward); } @@ -349,12 +315,6 @@ module sui::sui_system { validator_set::validator_delegate_amount(&self.validators, validator_addr) } - /// Returns the amount of delegators who have delegated to `validator_addr`. - /// Aborts if `validator_addr` is not an active validator. - public fun validator_delegator_count(self: &SuiSystemState, validator_addr: address): u64 { - validator_set::validator_delegator_count(&self.validators, validator_addr) - } - #[test_only] public fun set_epoch_for_testing(self: &mut SuiSystemState, epoch_num: u64) { self.epoch = epoch_num diff --git a/crates/sui-framework/sources/governance/validator.move b/crates/sui-framework/sources/governance/validator.move index 1dbf61c6907b9..7288698148f79 100644 --- a/crates/sui-framework/sources/governance/validator.move +++ b/crates/sui-framework/sources/governance/validator.move @@ -8,12 +8,13 @@ module sui::validator { use sui::balance::{Self, Balance}; use sui::sui::SUI; - use sui::tx_context::TxContext; + use sui::tx_context::{Self, TxContext}; use sui::stake; use sui::stake::Stake; use sui::epoch_time_lock::EpochTimeLock; use std::option::Option; use sui::crypto::Self; + use sui::staking_pool::{Self, Delegation, StakedSui, StakingPool}; friend sui::genesis; friend sui::sui_system; @@ -56,26 +57,14 @@ module sui::validator { /// The current active stake amount. This will not change during an epoch. It can only /// be updated at the end of epoch. stake_amount: u64, - /// Amount of delegated stake from token holders. - delegation: u64, /// Pending stake deposit amount, processed at end of epoch. pending_stake: u64, /// Pending withdraw amount, processed at end of epoch. pending_withdraw: u64, - /// Pending delegation deposits. - pending_delegation: u64, - /// Pending delegation withdraws. - pending_delegation_withdraw: u64, - /// Number of delegators that is currently delegating token to this validator. - /// This is used to create EpochRewardRecord, to help track how many delegators - /// have not yet claimed their reward. - delegator_count: u64, - /// Number of new delegators that will become effective in the next epoch. - pending_delegator_count: u64, - /// Number of delegators that will withdraw stake at the end of the epoch. - pending_delegator_withdraw_count: u64, /// Gas price quote, updated only at end of epoch. gas_price: u64, + /// Staking pool for the stakes delegated to this validator. + delegation_staking_pool: StakingPool, } const PROOF_OF_POSSESSION_DOMAIN: vector = vector[107, 111, 115, 107]; @@ -136,32 +125,23 @@ module sui::validator { next_epoch_gas_price: gas_price, }, stake_amount, - delegation: 0, pending_stake: 0, pending_withdraw: 0, - pending_delegation: 0, - pending_delegation_withdraw: 0, - delegator_count: 0, - pending_delegator_count: 0, - pending_delegator_withdraw_count: 0, gas_price, + delegation_staking_pool: staking_pool::new(sui_address, tx_context::epoch(ctx) + 1), } } - public(friend) fun destroy(self: Validator) { + public(friend) fun destroy(self: Validator, ctx: &mut TxContext) { let Validator { metadata: _, stake_amount: _, - delegation: _, pending_stake: _, pending_withdraw: _, - pending_delegation: _, - pending_delegation_withdraw: _, - delegator_count: _, - pending_delegator_count: _, - pending_delegator_withdraw_count: _, gas_price: _, + delegation_staking_pool, } = self; + staking_pool::deactivate_staking_pool(delegation_staking_pool, ctx); } /// Add stake to an active validator. The new stake is added to the pending_stake field, @@ -200,37 +180,56 @@ module sui::validator { self.stake_amount = self.stake_amount + self.pending_stake - self.pending_withdraw; self.pending_stake = 0; self.pending_withdraw = 0; + self.gas_price = self.metadata.next_epoch_gas_price; assert!(self.stake_amount == self.metadata.next_epoch_stake, 0); + } - self.delegation = self.delegation + self.pending_delegation - self.pending_delegation_withdraw; - self.pending_delegation = 0; - self.pending_delegation_withdraw = 0; + public(friend) fun request_add_delegation( + self: &mut Validator, + delegated_stake: Balance, + locking_period: Option, + ctx: &mut TxContext, + ) { + let delegate_amount = balance::value(&delegated_stake); + assert!(delegate_amount > 0, 0); + staking_pool::request_add_delegation(&mut self.delegation_staking_pool, delegated_stake, locking_period, ctx); - self.delegator_count = self.delegator_count + self.pending_delegator_count - self.pending_delegator_withdraw_count; - self.pending_delegator_count = 0; - self.pending_delegator_withdraw_count = 0; - assert!(self.delegation == self.metadata.next_epoch_delegation, 0); + increase_next_epoch_delegation(self, delegate_amount); + } - self.gas_price = self.metadata.next_epoch_gas_price; + public(friend) fun increase_next_epoch_delegation(self: &mut Validator, amount: u64) { + self.metadata.next_epoch_delegation = self.metadata.next_epoch_delegation + amount; } - public(friend) fun request_add_delegation(self: &mut Validator, delegate_amount: u64) { - assert!(delegate_amount > 0, 0); - self.pending_delegation = self.pending_delegation + delegate_amount; - self.pending_delegator_count = self.pending_delegator_count + 1; - self.metadata.next_epoch_delegation = self.metadata.next_epoch_delegation + delegate_amount; + public(friend) fun request_withdraw_delegation( + self: &mut Validator, + delegation: &mut Delegation, + staked_sui: &mut StakedSui, + withdraw_amount: u64, + ctx: &mut TxContext, + ) { + staking_pool::withdraw_stake(&mut self.delegation_staking_pool, delegation, staked_sui, withdraw_amount, ctx); + decrease_next_epoch_delegation(self, withdraw_amount); } - public(friend) fun request_remove_delegation(self: &mut Validator, delegate_amount: u64) { - self.pending_delegation_withdraw = self.pending_delegation_withdraw + delegate_amount; - self.pending_delegator_withdraw_count = self.pending_delegator_withdraw_count + 1; - self.metadata.next_epoch_delegation = self.metadata.next_epoch_delegation - delegate_amount; + public(friend) fun decrease_next_epoch_delegation(self: &mut Validator, amount: u64) { + self.metadata.next_epoch_delegation = self.metadata.next_epoch_delegation - amount; } public(friend) fun request_set_gas_price(self: &mut Validator, new_price: u64) { self.metadata.next_epoch_gas_price = new_price; } + public(friend) fun distribute_rewards_and_new_delegations(self: &mut Validator, reward: Balance, ctx: &mut TxContext) { + self.metadata.next_epoch_delegation = self.metadata.next_epoch_delegation + balance::value(&reward); + staking_pool::advance_epoch(&mut self.delegation_staking_pool, reward, ctx); + assert!(delegate_amount(self) == self.metadata.next_epoch_delegation, 0); + } + + public(friend) fun get_staking_pool_mut_ref(self: &mut Validator) : &mut StakingPool { + &mut self.delegation_staking_pool + } + public fun metadata(self: &Validator): &ValidatorMetadata { &self.metadata } @@ -244,11 +243,7 @@ module sui::validator { } public fun delegate_amount(self: &Validator): u64 { - self.delegation - } - - public fun delegator_count(self: &Validator): u64 { - self.delegator_count + staking_pool::sui_balance(&self.delegation_staking_pool) } public fun pending_stake_amount(self: &Validator): u64 { @@ -306,15 +301,10 @@ module sui::validator { next_epoch_gas_price: gas_price, }, stake_amount, - delegation: 0, pending_stake: 0, pending_withdraw: 0, - pending_delegation: 0, - pending_delegation_withdraw: 0, - delegator_count: 0, - pending_delegator_count: 0, - pending_delegator_withdraw_count: 0, gas_price, + delegation_staking_pool: staking_pool::new(sui_address, tx_context::epoch(ctx) + 1), } } } diff --git a/crates/sui-framework/sources/governance/validator_set.move b/crates/sui-framework/sources/governance/validator_set.move index 25b9130589d7d..c763c369018d5 100644 --- a/crates/sui-framework/sources/governance/validator_set.move +++ b/crates/sui-framework/sources/governance/validator_set.move @@ -6,11 +6,11 @@ module sui::validator_set { use std::vector; use sui::balance::{Self, Balance}; - use sui::epoch_reward_record; use sui::sui::SUI; use sui::tx_context::{Self, TxContext}; use sui::validator::{Self, Validator, ValidatorMetadata}; use sui::stake::Stake; + use sui::staking_pool::{Self, Delegation, StakedSui}; use sui::epoch_time_lock::EpochTimeLock; use sui::priority_queue as pq; @@ -142,30 +142,12 @@ module sui::validator_set { public(friend) fun request_add_delegation( self: &mut ValidatorSet, validator_address: address, - delegate_amount: u64, + delegated_stake: Balance, + locking_period: Option, + ctx: &mut TxContext, ) { let validator = get_validator_mut(&mut self.active_validators, validator_address); - validator::request_add_delegation(validator, delegate_amount); - self.next_epoch_validators = derive_next_epoch_validators(self); - } - - public(friend) fun request_remove_delegation( - self: &mut ValidatorSet, - validator_address: address, - delegate_amount: u64, - ) { - let validator_index_opt = find_validator(&self.active_validators, validator_address); - // It's OK to not be able to find the validator. This can happen if the delegated - // validator is no longer active. - if (option::is_some(&validator_index_opt)) { - let validator_index = option::extract(&mut validator_index_opt); - let validator = vector::borrow_mut(&mut self.active_validators, validator_index); - validator::request_remove_delegation(validator, delegate_amount); - } else { - // TODO: How do we deal with undelegating from inactive validators? - // https://github.com/MystenLabs/sui/issues/2837 - abort 0 - }; + validator::request_add_delegation(validator, delegated_stake, locking_period, ctx); self.next_epoch_validators = derive_next_epoch_validators(self); } @@ -179,27 +161,51 @@ module sui::validator_set { validator::request_set_gas_price(validator, new_gas_price); } - public(friend) fun create_epoch_records( - self: &ValidatorSet, - epoch: u64, - computation_charge: u64, - total_stake: u64, + + public(friend) fun request_withdraw_delegation( + self: &mut ValidatorSet, + delegation: &mut Delegation, + staked_sui: &mut StakedSui, + withdraw_amount: u64, ctx: &mut TxContext, ) { - let length = vector::length(&self.active_validators); - let i = 0; - while (i < length) { - let v = vector::borrow(&self.active_validators, i); - epoch_reward_record::create( - epoch, - computation_charge, - total_stake, - validator::delegator_count(v), - validator::sui_address(v), - ctx, - ); - i = i + 1; - } + let validator_address = staking_pool::validator_address(delegation); + let validator_index_opt = find_validator(&self.active_validators, validator_address); + + assert!(option::is_some(&validator_index_opt), 0); + + let validator_index = option::extract(&mut validator_index_opt); + let validator = vector::borrow_mut(&mut self.active_validators, validator_index); + validator::request_withdraw_delegation(validator, delegation, staked_sui, withdraw_amount, ctx); + self.next_epoch_validators = derive_next_epoch_validators(self); + } + + public(friend) fun request_switch_delegation( + self: &mut ValidatorSet, + delegation: Delegation, + staked_sui: &mut StakedSui, + new_validator_address: address, + ctx: &mut TxContext, + ) { + let current_validator_address = staking_pool::validator_address(&delegation); + assert!(current_validator_address != new_validator_address, 0); + + let current_validator_index_opt = find_validator(&self.active_validators, current_validator_address); + assert!(option::is_some(¤t_validator_index_opt), 0); + + // withdraw stake and compounded rewards from the current validator's pool + let current_validator_index = option::extract(&mut current_validator_index_opt); + let current_validator = vector::borrow_mut(&mut self.active_validators, current_validator_index); + let (principal_stake, rewards_stake, time_lock) = + staking_pool::withdraw_all_to_sui_tokens(validator::get_staking_pool_mut_ref(current_validator), delegation, staked_sui); + let withdraw_sui_amount = balance::value(&principal_stake) + balance::value(&rewards_stake); + validator::decrease_next_epoch_delegation(current_validator, withdraw_sui_amount); + + // and deposit into the new validator's pool + request_add_delegation(self, new_validator_address, principal_stake, time_lock, ctx); + request_add_delegation(self, new_validator_address, rewards_stake, option::none(), ctx); + + self.next_epoch_validators = derive_next_epoch_validators(self); } /// Update the validator set at the end of epoch. @@ -210,26 +216,36 @@ module sui::validator_set { /// 4. At the end, we calculate the total stake for the new epoch. public(friend) fun advance_epoch( self: &mut ValidatorSet, - computation_reward: &mut Balance, + validator_reward: &mut Balance, + delegator_reward: &mut Balance, ctx: &mut TxContext, ) { // `compute_reward_distribution` must be called before `adjust_stake` to make sure we are using the current // epoch's stake information to compute reward distribution. - let rewards = compute_reward_distribution( + let (validator_reward_amounts, delegator_reward_amounts) = compute_reward_distribution( &self.active_validators, self.total_validator_stake, - balance::value(computation_reward), + balance::value(validator_reward), + self.total_delegation_stake, + balance::value(delegator_reward), ); // `adjust_stake_and_gas_price` must be called before `distribute_reward`, because reward distribution goes to // each validator's pending stake, and that shouldn't be available in the next epoch. adjust_stake_and_gas_price(&mut self.active_validators); - distribute_reward(&mut self.active_validators, &rewards, computation_reward, ctx); + distribute_reward( + &mut self.active_validators, + &validator_reward_amounts, + validator_reward, + &delegator_reward_amounts, + delegator_reward, + ctx + ); process_pending_validators(&mut self.active_validators, &mut self.pending_validators); - process_pending_removals(&mut self.active_validators, &mut self.pending_removals); + process_pending_removals(self, ctx); self.next_epoch_validators = derive_next_epoch_validators(self); @@ -287,11 +303,6 @@ module sui::validator_set { validator::delegate_amount(validator) } - public fun validator_delegator_count(self: &ValidatorSet, validator_address: address): u64 { - let validator = get_validator_ref(&self.active_validators, validator_address); - validator::delegator_count(validator) - } - /// Checks whether a duplicate of `new_validator` is already in `validators`. /// Two validators duplicate if they share the same sui_address or same IP or same name. fun contains_duplicate_validator(validators: &vector, new_validator: &Validator): bool { @@ -346,13 +357,15 @@ module sui::validator_set { /// Process the pending withdraw requests. For each pending request, the validator /// is removed from `validators` and sent back to the address of the validator. fun process_pending_removals( - validators: &mut vector, withdraw_list: &mut vector + self: &mut ValidatorSet, + ctx: &mut TxContext, ) { - sort_removal_list(withdraw_list); - while (!vector::is_empty(withdraw_list)) { - let index = vector::pop_back(withdraw_list); - let validator = vector::remove(validators, index); - validator::destroy(validator); + sort_removal_list(&mut self.pending_removals); + while (!vector::is_empty(&self.pending_removals)) { + let index = vector::pop_back(&mut self.pending_removals); + let validator = vector::remove(&mut self.active_validators, index); + self.total_delegation_stake = self.total_delegation_stake - validator::delegate_amount(&validator); + validator::destroy(validator, ctx); } } @@ -429,8 +442,11 @@ module sui::validator_set { validators: &vector, total_stake: u64, total_reward: u64, - ): vector { - let results = vector::empty(); + total_delegation_stake: u64, + total_delegation_reward: u64, + ): (vector, vector) { + let validator_reward_amounts = vector::empty(); + let delegator_reward_amounts = vector::empty(); let length = vector::length(validators); let i = 0; while (i < length) { @@ -440,27 +456,40 @@ module sui::validator_set { // Use u128 to avoid multiplication overflow. let stake_amount: u128 = (validator::stake_amount(validator) as u128); let reward_amount = stake_amount * (total_reward as u128) / (total_stake as u128); - vector::push_back(&mut results, (reward_amount as u64)); + vector::push_back(&mut validator_reward_amounts, (reward_amount as u64)); + + let delegation_stake_amount: u128 = (validator::delegate_amount(validator) as u128); + let delegation_reward_amount = + if (total_delegation_stake == 0) 0 + else delegation_stake_amount * (total_delegation_reward as u128) / (total_delegation_stake as u128); + vector::push_back(&mut delegator_reward_amounts, (delegation_reward_amount as u64)); + i = i + 1; }; - results + (validator_reward_amounts, delegator_reward_amounts) } - // TODO: Allow reward compunding for delegators. fun distribute_reward( validators: &mut vector, - rewards: &vector, - reward: &mut Balance, + validator_reward_amounts: &vector, + validator_rewards: &mut Balance, + delegator_reward_amounts: &vector, + delegator_rewards: &mut Balance, ctx: &mut TxContext ) { let length = vector::length(validators); let i = 0; while (i < length) { let validator = vector::borrow_mut(validators, i); - let reward_amount = *vector::borrow(rewards, i); - let reward = balance::split(reward, reward_amount); + let reward_amount = *vector::borrow(validator_reward_amounts, i); + let reward = balance::split(validator_rewards, reward_amount); // Because reward goes to pending stake, it's the same as calling `request_add_stake`. validator::request_add_stake(validator, reward, option::none(), ctx); + + let delegator_reward_amount = *vector::borrow(delegator_reward_amounts, i); + let delegator_reward = balance::split(delegator_rewards, delegator_reward_amount); + // Add rewards to delegation staking pool to auto compound for delegators. + validator::distribute_rewards_and_new_delegations(validator, delegator_reward, ctx); i = i + 1; } } @@ -514,7 +543,7 @@ module sui::validator_set { } = self; while (!vector::is_empty(&active_validators)) { let v = vector::pop_back(&mut active_validators); - validator::destroy(v); + validator::destroy(v, &mut tx_context::dummy()); }; vector::destroy_empty(active_validators); vector::destroy_empty(pending_validators); diff --git a/crates/sui-framework/sources/locked_coin.move b/crates/sui-framework/sources/locked_coin.move index 267f92e2cb760..faf78149e67aa 100644 --- a/crates/sui-framework/sources/locked_coin.move +++ b/crates/sui-framework/sources/locked_coin.move @@ -9,7 +9,6 @@ module sui::locked_coin { use sui::tx_context::{Self, TxContext}; use sui::epoch_time_lock::{Self, EpochTimeLock}; - friend sui::delegation; friend sui::sui_system; /// A coin of type `T` locked until `locked_until_epoch`. diff --git a/crates/sui-framework/sources/vec_map.move b/crates/sui-framework/sources/vec_map.move index 304e48e93b6f5..bbce5450acd3f 100644 --- a/crates/sui-framework/sources/vec_map.move +++ b/crates/sui-framework/sources/vec_map.move @@ -17,6 +17,9 @@ module sui::vec_map { /// Trying to access an element of the map at an invalid index const EIndexOutOfBounds: u64 = 3; + /// Trying to pop from a map that is empty + const EMapEmpty: u64 = 4; + /// A map data structure backed by a vector. The map is guaranteed not to contain duplicate keys, but entries /// are *not* sorted by key--entries are included in insertion order. /// All operations are O(N) in the size of the map--the intention of this data structure is only to provide @@ -52,6 +55,13 @@ module sui::vec_map { (key, value) } + /// Pop the most recently inserted entry from the map. Aborts if the map is empty. + public fun pop(self: &mut VecMap): (K, V) { + assert!(!vector::is_empty(&self.contents), EMapEmpty); + let Entry { key, value } = vector::pop_back(&mut self.contents); + (key, value) + } + /// Get a mutable reference to the value bound to `key` in `self`. /// Aborts if `key` is not bound in `self`. public fun get_mut(self: &mut VecMap, key: &K): &mut V { diff --git a/crates/sui-framework/tests/delegation_tests.move b/crates/sui-framework/tests/delegation_tests.move index 4536ae7f48987..e7d3f4e656a4f 100644 --- a/crates/sui-framework/tests/delegation_tests.move +++ b/crates/sui-framework/tests/delegation_tests.move @@ -1,13 +1,14 @@ // Copyright (c) 2022, Mysten Labs, Inc. // SPDX-License-Identifier: Apache-2.0 +// TODO: add tests for checking the maths of reward distribution here, and tests for bonding period too. #[test_only] module sui::delegation_tests { use sui::coin; - use sui::epoch_reward_record::EpochRewardRecord; use sui::test_scenario::{Self, Scenario}; use sui::sui_system::{Self, SuiSystemState}; - use sui::delegation::{Self, Delegation}; + use sui::staking_pool::{Self, Delegation, StakedSui}; + use sui::governance_test_utils::{ Self, create_validator_for_testing, @@ -38,187 +39,48 @@ module sui::delegation_tests { sui_system::request_add_delegation( system_state_mut_ref, coin::mint_for_testing(60, ctx), VALIDATOR_ADDR_1, ctx); - // Advance the epoch so that the delegation changes can take into effect. - governance_test_utils::advance_epoch(system_state_mut_ref, scenario); - - // Check that the delegation amount and count are changed correctly. - assert!(sui_system::validator_delegate_amount(system_state_mut_ref, VALIDATOR_ADDR_1) == 70, 101); + assert!(sui_system::validator_delegate_amount(system_state_mut_ref, VALIDATOR_ADDR_1) == 0, 101); assert!(sui_system::validator_delegate_amount(system_state_mut_ref, VALIDATOR_ADDR_2) == 0, 102); - assert!(sui_system::validator_delegator_count(system_state_mut_ref, VALIDATOR_ADDR_1) == 2, 103); - assert!(sui_system::validator_delegator_count(system_state_mut_ref, VALIDATOR_ADDR_2) == 0, 104); - test_scenario::return_shared(scenario, system_state_wrapper); - }; - - - test_scenario::next_tx(scenario, &DELEGATOR_ADDR_1); - { - - let delegation = test_scenario::take_last_created_owned(scenario); - assert!(delegation::delegate_amount(&delegation) == 60, 105); - - - let system_state_wrapper = test_scenario::take_shared(scenario); - let system_state_mut_ref = test_scenario::borrow_mut(&mut system_state_wrapper); - - let ctx = test_scenario::ctx(scenario); - - // Undelegate 60 SUIs from VALIDATOR_ADDR_1 - sui_system::request_remove_delegation( - system_state_mut_ref, &mut delegation, ctx); - - // Check that the delegation object indeed becomes inactive. - assert!(!delegation::is_active(&delegation), 106); - test_scenario::return_owned(scenario, delegation); governance_test_utils::advance_epoch(system_state_mut_ref, scenario); - assert!(sui_system::validator_delegate_amount(system_state_mut_ref, VALIDATOR_ADDR_1) == 10, 107); - assert!(sui_system::validator_delegator_count(system_state_mut_ref, VALIDATOR_ADDR_1) == 1, 108); + // The amount hasn't changed yet because delegation is not activated + assert!(sui_system::validator_delegate_amount(system_state_mut_ref, VALIDATOR_ADDR_1) == 70, 103); + assert!(sui_system::validator_delegate_amount(system_state_mut_ref, VALIDATOR_ADDR_2) == 0, 104); test_scenario::return_shared(scenario, system_state_wrapper); }; - } - - #[test] - fun test_switch_delegation_flow() { - let scenario = &mut test_scenario::begin(&VALIDATOR_ADDR_1); - set_up_sui_system_state(scenario); - - test_scenario::next_tx(scenario, &DELEGATOR_ADDR_1); - { - let system_state_wrapper = test_scenario::take_shared(scenario); - let system_state_mut_ref = test_scenario::borrow_mut(&mut system_state_wrapper); - - let ctx = test_scenario::ctx(scenario); - - // Create one delegation to VALIDATOR_ADDR_1, and one to VALIDATOR_ADDR_2. - sui_system::request_add_delegation( - system_state_mut_ref, coin::mint_for_testing(60, ctx), VALIDATOR_ADDR_1, ctx); - sui_system::request_add_delegation( - system_state_mut_ref, coin::mint_for_testing(10, ctx), VALIDATOR_ADDR_2, ctx); - - governance_test_utils::advance_epoch(system_state_mut_ref, scenario); - test_scenario::return_shared(scenario, system_state_wrapper); - }; - + test_scenario::next_tx(scenario, &DELEGATOR_ADDR_1); { let delegation = test_scenario::take_last_created_owned(scenario); - - let system_state_wrapper = test_scenario::take_shared(scenario); - let system_state_mut_ref = test_scenario::borrow_mut(&mut system_state_wrapper); - - let ctx = test_scenario::ctx(scenario); - - // Switch the 10 SUI delegation from VALIDATOR_ADDR_2 to VALIDATOR_ADDR_1 - sui_system::request_switch_delegation( - system_state_mut_ref, &mut delegation, VALIDATOR_ADDR_1, ctx); - - test_scenario::return_owned(scenario, delegation); - - governance_test_utils::advance_epoch(system_state_mut_ref, scenario); - - // Check that now VALIDATOR_ADDR_1 has all the delegations - assert!(sui_system::validator_delegate_amount(system_state_mut_ref, VALIDATOR_ADDR_1) == 70, 101); - assert!(sui_system::validator_delegate_amount(system_state_mut_ref, VALIDATOR_ADDR_2) == 0, 102); - assert!(sui_system::validator_delegator_count(system_state_mut_ref, VALIDATOR_ADDR_1) == 2, 103); - assert!(sui_system::validator_delegator_count(system_state_mut_ref, VALIDATOR_ADDR_2) == 0, 104); - test_scenario::return_shared(scenario, system_state_wrapper); - }; - } + assert!(staking_pool::delegation_token_amount(&delegation) == 70, 105); - #[test] - #[expected_failure(abort_code = 0)] - fun test_double_claim_reward_active() { - let scenario = &mut test_scenario::begin(&VALIDATOR_ADDR_1); - let ctx = test_scenario::ctx(scenario); - create_sui_system_state_for_testing( - vector[create_validator_for_testing(VALIDATOR_ADDR_1, 100, ctx)], 300, 100); + let staked_sui = test_scenario::take_last_created_owned(scenario); + assert!(staking_pool::staked_sui_amount(&staked_sui) == 60, 105); - test_scenario::next_tx(scenario, &DELEGATOR_ADDR_1); - { + let system_state_wrapper = test_scenario::take_shared(scenario); let system_state_mut_ref = test_scenario::borrow_mut(&mut system_state_wrapper); let ctx = test_scenario::ctx(scenario); - sui_system::request_add_delegation( - system_state_mut_ref, coin::mint_for_testing(10, ctx), VALIDATOR_ADDR_1, ctx); - - // Advance the epoch twice so that the delegation and rewards can take into effect. - governance_test_utils::advance_epoch(system_state_mut_ref, scenario); - governance_test_utils::advance_epoch(system_state_mut_ref, scenario); - test_scenario::return_shared(scenario, system_state_wrapper); - }; - - test_scenario::next_tx(scenario, &DELEGATOR_ADDR_1); - { - let delegation = test_scenario::take_last_created_owned(scenario); - let system_state_wrapper = test_scenario::take_shared(scenario); - let system_state_mut_ref = test_scenario::borrow_mut(&mut system_state_wrapper); - let epoch_reward_record_wrapper = test_scenario::take_last_created_shared(scenario); - let epoch_reward_record_ref = test_scenario::borrow_mut(&mut epoch_reward_record_wrapper); - let ctx = test_scenario::ctx(scenario); - - sui_system::claim_delegation_reward(system_state_mut_ref, &mut delegation, epoch_reward_record_ref, ctx); - - // We are claiming the same reward twice so this call should fail. - sui_system::claim_delegation_reward(system_state_mut_ref, &mut delegation, epoch_reward_record_ref, ctx); + // Undelegate 40 SUI from VALIDATOR_ADDR_1 + sui_system::request_withdraw_delegation( + system_state_mut_ref, &mut delegation, &mut staked_sui, 40, ctx); + assert!(staking_pool::delegation_token_amount(&delegation) == 30, 106); test_scenario::return_owned(scenario, delegation); - test_scenario::return_shared(scenario, epoch_reward_record_wrapper); - test_scenario::return_shared(scenario, system_state_wrapper); - } + assert!(staking_pool::staked_sui_amount(&staked_sui) == 20, 106); + test_scenario::return_owned(scenario, staked_sui); - } + assert!(sui_system::validator_delegate_amount(system_state_mut_ref, VALIDATOR_ADDR_1) == 70, 107); - #[test] - #[expected_failure(abort_code = 0)] - fun test_double_claim_reward_inactive() { - let scenario = &mut test_scenario::begin(&VALIDATOR_ADDR_1); - let ctx = test_scenario::ctx(scenario); - create_sui_system_state_for_testing( - vector[create_validator_for_testing(VALIDATOR_ADDR_1, 100, ctx)], 300, 100); - - test_scenario::next_tx(scenario, &DELEGATOR_ADDR_1); - { - let system_state_wrapper = test_scenario::take_shared(scenario); - let system_state_mut_ref = test_scenario::borrow_mut(&mut system_state_wrapper); - - let ctx = test_scenario::ctx(scenario); - - sui_system::request_add_delegation( - system_state_mut_ref, coin::mint_for_testing(10, ctx), VALIDATOR_ADDR_1, ctx); - sui_system::request_add_delegation( - system_state_mut_ref, coin::mint_for_testing(20, ctx), VALIDATOR_ADDR_1, ctx); - - // Advance the epoch twice so that the delegation and rewards can take into effect. - governance_test_utils::advance_epoch(system_state_mut_ref, scenario); governance_test_utils::advance_epoch(system_state_mut_ref, scenario); - test_scenario::return_shared(scenario, system_state_wrapper); - }; - test_scenario::next_tx(scenario, &DELEGATOR_ADDR_1); - { - let delegation = test_scenario::take_last_created_owned(scenario); - let system_state_wrapper = test_scenario::take_shared(scenario); - let system_state_mut_ref = test_scenario::borrow_mut(&mut system_state_wrapper); - let epoch_reward_record_wrapper = test_scenario::take_last_created_shared(scenario); - let epoch_reward_record_ref = test_scenario::borrow_mut(&mut epoch_reward_record_wrapper); - let ctx = test_scenario::ctx(scenario); - - // Remove delegation. Rewards claiming should still work. - sui_system::request_remove_delegation(system_state_mut_ref, &mut delegation, ctx); - sui_system::claim_delegation_reward(system_state_mut_ref, &mut delegation, epoch_reward_record_ref, ctx); - - // We are claiming the same reward twice so this call should fail. - sui_system::claim_delegation_reward(system_state_mut_ref, &mut delegation, epoch_reward_record_ref, ctx); - - test_scenario::return_owned(scenario, delegation); - test_scenario::return_shared(scenario, epoch_reward_record_wrapper); + assert!(sui_system::validator_delegate_amount(system_state_mut_ref, VALIDATOR_ADDR_1) == 30, 107); test_scenario::return_shared(scenario, system_state_wrapper); }; - } fun set_up_sui_system_state(scenario: &mut Scenario) { diff --git a/crates/sui-framework/tests/validator_set_tests.move b/crates/sui-framework/tests/validator_set_tests.move index 84cccf0a8d940..24ad25f204bf4 100644 --- a/crates/sui-framework/tests/validator_set_tests.move +++ b/crates/sui-framework/tests/validator_set_tests.move @@ -80,8 +80,9 @@ module sui::validator_set_tests { test_scenario::next_tx(&mut scenario, &@0x1); { let reward = balance::zero(); + let delegation_reward = balance::zero(); let ctx1 = test_scenario::ctx(&mut scenario); - validator_set::advance_epoch(&mut validator_set, &mut reward, ctx1); + validator_set::advance_epoch(&mut validator_set, &mut reward, &mut delegation_reward, ctx1); // The total stake and quorum should reflect 4 validators. assert!(validator_set::next_epoch_validator_count(&validator_set) == 4, 0); assert!(validator_set::total_validator_stake(&validator_set) == 1000, 0); @@ -93,10 +94,11 @@ module sui::validator_set_tests { // Total validator candidate count changes, but total stake remains during epoch. assert!(validator_set::next_epoch_validator_count(&validator_set) == 3, 0); assert!(validator_set::total_validator_stake(&validator_set) == 1000, 0); - validator_set::advance_epoch(&mut validator_set, &mut reward, ctx1); + validator_set::advance_epoch(&mut validator_set, &mut reward, &mut delegation_reward, ctx1); // Validator1 is gone. assert!(validator_set::total_validator_stake(&validator_set) == 900, 0); balance::destroy_zero(reward); + balance::destroy_zero(delegation_reward); }; validator_set::destroy_for_testing(validator_set); @@ -107,6 +109,7 @@ module sui::validator_set_tests { let scenario = test_scenario::begin(&@0x1); let ctx1 = test_scenario::ctx(&mut scenario); let dummy_balance = balance::zero(); + let dummy_delegator_reward = balance::zero(); // Create 5 validators with different stakes and different gas prices. let v1 = create_validator_with_gas_price(@0x1, 1, 45, ctx1); let v2 = create_validator_with_gas_price(@0x2, 2, 42, ctx1); @@ -123,7 +126,7 @@ module sui::validator_set_tests { &mut validator_set, v2, ); - validator_set::advance_epoch(&mut validator_set, &mut dummy_balance, ctx1); + validator_set::advance_epoch(&mut validator_set, &mut dummy_balance, &mut dummy_delegator_reward, ctx1); assert!(validator_set::derive_reference_gas_price(&validator_set) == 45, 1); @@ -131,7 +134,7 @@ module sui::validator_set_tests { &mut validator_set, v3, ); - validator_set::advance_epoch(&mut validator_set, &mut dummy_balance, ctx1); + validator_set::advance_epoch(&mut validator_set, &mut dummy_balance, &mut dummy_delegator_reward, ctx1); assert!(validator_set::derive_reference_gas_price(&validator_set) == 42, 2); @@ -139,7 +142,7 @@ module sui::validator_set_tests { &mut validator_set, v4, ); - validator_set::advance_epoch(&mut validator_set, &mut dummy_balance, ctx1); + validator_set::advance_epoch(&mut validator_set, &mut dummy_balance, &mut dummy_delegator_reward, ctx1); assert!(validator_set::derive_reference_gas_price(&validator_set) == 41, 3); @@ -147,12 +150,13 @@ module sui::validator_set_tests { &mut validator_set, v5, ); - validator_set::advance_epoch(&mut validator_set, &mut dummy_balance, ctx1); + validator_set::advance_epoch(&mut validator_set, &mut dummy_balance, &mut dummy_delegator_reward, ctx1); assert!(validator_set::derive_reference_gas_price(&validator_set) == 43, 4); validator_set::destroy_for_testing(validator_set); balance::destroy_zero(dummy_balance); + balance::destroy_zero(dummy_delegator_reward); } fun create_validator(addr: address, hint: u8, ctx: &mut TxContext): Validator { diff --git a/crates/sui-framework/tests/validator_tests.move b/crates/sui-framework/tests/validator_tests.move index 72691450ad17d..3fc6023929bba 100644 --- a/crates/sui-framework/tests/validator_tests.move +++ b/crates/sui-framework/tests/validator_tests.move @@ -36,7 +36,7 @@ module sui::validator_tests { assert!(validator::stake_amount(&validator) == 10, 0); assert!(validator::sui_address(&validator) == sender, 0); - validator::destroy(validator); + validator::destroy(validator, ctx); }; // Check that after destroy, the original stake still exists. @@ -103,6 +103,6 @@ module sui::validator_tests { test_scenario::return_owned(scenario, withdraw); }; - validator::destroy(validator); + validator::destroy(validator, test_scenario::ctx(scenario)); } } diff --git a/crates/sui-types/src/sui_system_state.rs b/crates/sui-types/src/sui_system_state.rs index 2019c504969a7..47978a75cab7a 100644 --- a/crates/sui-types/src/sui_system_state.rs +++ b/crates/sui-types/src/sui_system_state.rs @@ -24,7 +24,7 @@ pub struct SystemParameters { pub storage_gas_price: u64, } -/// Rust version of the Move Std::Option::Option type. +/// Rust version of the Move std::option::Option type. /// Putting it in this file because it's only used here. #[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] pub struct MoveOption { @@ -49,15 +49,29 @@ pub struct ValidatorMetadata { pub struct Validator { pub metadata: ValidatorMetadata, pub stake_amount: u64, - pub delegation: u64, pub pending_stake: u64, pub pending_withdraw: u64, - pub pending_delegation: u64, - pub pending_delegation_withdraw: u64, - pub delegator_count: u64, - pub pending_delegator_count: u64, - pub pending_delegator_withdraw_count: u64, pub gas_price: u64, + pub delegation_staking_pool: StakingPool, +} + +/// Rust version of the Move sui::staking_pool::PendingDelegationEntry type. +#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] +pub struct PendingDelegationEntry { + pub delegator: AccountAddress, + pub sui_amount: u64, +} + +/// Rust version of the Move sui::staking_pool::StakingPool type +#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] +pub struct StakingPool { + pub validator_address: AccountAddress, + pub starting_epoch: u64, + pub epoch_starting_sui_balance: u64, + pub sui_balance: u64, + pub rewards_pool: Balance, + pub delegation_token_supply: Supply, + pub pending_delegations: Vec, } /// Rust version of the Move sui::validator_set::ValidatorSet type @@ -81,7 +95,6 @@ pub struct SuiSystemState { pub treasury_cap: Supply, pub storage_fund: Balance, pub parameters: SystemParameters, - pub delegation_reward: Balance, pub reference_gas_price: u64, // TODO: Use getters instead of all pub. }